Christopher Markieta
Christopher Markieta

Reputation: 5913

How do I add a self-signed root certificate authority to a device?

How do I install a root certificate authority on a device?

The certificate is only needed for my app, and can be installed in its sandbox if possible.

It works when I drag the certificate onto the simulator and install it, but not using the following code:

let rootCertPath = NSBundle.mainBundle().pathForResource("server", ofType: "der")!
let rootCertData = NSData(contentsOfFile: rootCertPath)!
let rootCert     = SecCertificateCreateWithData(kCFAllocatorDefault, rootCertData).takeRetainedValue()

let error = SecItemAdd(
[
    NSString(format: kSecClass):    NSString(format: kSecClassCertificate),
    NSString(format: kSecValueRef): rootCert
], nil)

SecItemAdd returns with no errors, and seems to be installed on the device correctly, but it still fails to connect to the server with with the error:

NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

Code for connecting to server:

let request = NSURLRequest(URL: NSURL(string: "https://" + server + ":" + port)!)
let session = NSURLSession(configuration: .defaultSessionConfiguration())

session.dataTaskWithRequest(request, completionHandler:
{(data, response, error) in
    println(error)
}).resume()

error prints the following:

Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid.

But again, if I manually install the same certificate in the simulator's profiles, it connects just fine.

Upvotes: 3

Views: 1176

Answers (1)

Christopher Markieta
Christopher Markieta

Reputation: 5913

This is not safe and does not require the certificate

Managed to get this working using sockets (NSStream and CFStream).

The important thing to note is that I needed to disable kCFStreamSSLValidatesCertificateChain for my certificate to work.

class Authentication: NSObject, NSStreamDelegate
{
    private var  inputStream: NSInputStream?
    private var outputStream: NSOutputStream?

    func connectToServer(server: String, port: Int)
    {   
        let sslSettings =
        [
            NSString(format: kCFStreamSSLValidatesCertificateChain): kCFBooleanFalse
        ]

        NSStream.getStreamsToHostWithName(server, port: port, inputStream: &inputStream, outputStream: &outputStream)

        CFReadStreamSetProperty(inputStream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelTLSv1)
        CFReadStreamSetProperty(inputStream, kCFStreamPropertySSLSettings, sslSettings)

         inputStream!.delegate = self
        outputStream!.delegate = self

         inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
        outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

         inputStream!.open()
        outputStream!.open()
    }
}

Helpful links:

iOS: Pre install SSL certificate in keychain - programmatically

Overriding TLS Chain Validation Correctly

HTTPS Server Trust Evaluation

SSL Socket connection iOS

Toll-free bridging and pointer access in Swift

Adding a self-signed certificate to iphone Simulator?

Upvotes: 1

Related Questions