Reputation: 4430
I am working on a project that requires client certificate support with websockets. I am currently using Starscream, however unfortunately from reading the documentation, it does not seem to have any information regarding support for this. I have looked around at few other swift web socket libraries, but none of them mention support for this
Does anyone know of any libraries that support such functionality?
Any information would be much appreciated!!
Edit:
So I am currently using Starscream to try this. I have got the certificate setup. here is the code I am trying so far
public struct IdentityAndTrust {
public var identityRef:SecIdentity
public var trust:SecTrust
public var certData : Data
}
var socket = WebSocket(url: URL(string: "\(ConstantKeys.ipAddress)")!, protocols: [])
var identityTest : IdentityAndTrust?
func createTrust()
{
do
{
let urlPath = Bundle.main.path(forResource: "client", ofType: "p12")
let url = NSURL.fileURL(withPath: urlPath!)
let certificateData = try Data(contentsOf: url)
identityTest = extractTrustAndIdentity(certData: certificateData, certPassword: ConstantKeys.password)
}
catch
{
print(error)
}
}
func extractTrustAndIdentity(certData:Data, certPassword:String) -> IdentityAndTrust
{
var identityAndTrust:IdentityAndTrust!
var securityError:OSStatus = errSecSuccess
var items: CFArray?
let certOptions: Dictionary = [ kSecImportExportPassphrase as String : certPassword ];
// import certificate to read its entries
securityError = SecPKCS12Import(certData as CFData, certOptions as CFDictionary, &items);
if securityError == errSecSuccess {
let certItems:CFArray = items as CFArray!;
let certItemsArray:Array = certItems as Array
let dict:AnyObject? = certItemsArray.first;
if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {
// grab the identity
let identityPointer:AnyObject? = certEntry["identity"];
let secIdentityRef:SecIdentity = identityPointer as! SecIdentity!;
// grab the trust
let trustPointer:AnyObject? = certEntry["trust"];
let trustRef:SecTrust = trustPointer as! SecTrust;
// grab the certificate chain
var certRef: SecCertificate?
SecIdentityCopyCertificate(secIdentityRef, &certRef);
let certArray:NSMutableArray = NSMutableArray();
certArray.add(certRef as SecCertificate!);
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certData : certData);
}
}
return identityAndTrust
}
I then connect socket like so
let key = SecTrustCopyPublicKey(identityTest!.trust)!;
let ssl = SSLCert(key: key)
socket.security = SSLSecurity(certs: [ssl], usePublicKeys: false)
socket.enabledSSLCipherSuites = [TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384]
socket.delegate = self
socket.connect()
But I got the following error message
CFNetwork SSLHandshake failed (-9807)
TCP Conn 0x604000173980 SSLHandshake failed (-9807) websocket is disconnected: The operation couldn’t be completed. (OSStatus error -9807.)
I know the certificate is valid as I use it to make https requests and it works fine. So does anyone know why it is not working? Or does anyone know of another socket library that would help with this issue?
Upvotes: 4
Views: 1292
Reputation: 864
You can do the SSL pinning by simply using NSURLSession (URLSession) without using any third party library but if you still want to use one, SocketRocket, AFNetworking have support for it.
The links below should help you:
http://www.yeradis.com/swift-authentication-challenge
http://www.indelible.org/ink/trusted-ssl-certificates/
https://jetforme.org/2013/05/validating-a-self-signed-ssl-certificate-in-ios-and-os-x-against-a-changing-host-name/enter link description here
Any methods you choose (third party or URLSession), I suggest that you do read this security issue:
https://github.com/facebook/SocketRocket/pull/534
https://www.synopsys.com/blogs/software-security/ineffective-certificate-pinning-implementations/enter link description here
Upvotes: 0