How to Secure Intranet API with Custom Certificate Authority on iOS

Written by micci | Published 2023/05/09
Tech Story Tags: ios-app-development | ios | ios-development | security | intranet | openssl | mobile-app-development | cybersecurity

TLDRIn this guide, we will show you how to secure an intranet API with your own Certificate Authority (CA) and make it trusted on an iOS app with no user intervention. Operating a CA requires secure key management, infrastructure protection, and in case of certificate compromisation, you will not be able to revoke a certificate.via the TL;DR App

In this guide, we will show you how to secure an intranet API with your own Certificate Authority (CA) and make it trusted on an iOS app with no user intervention.

Warning: Operating a CA requires secure key management, infrastructure protection, and in case of certificate compromisation, you will not be able to revoke a certificate.

Create Your Own Certificate Authority

First of all, you need to create your own Certificate Authority.

To do this, follow the step-by-step guide from Jamie Linux's OpenSSL Certificate Authority guide or use my script that will do all the work described in the link for you.

Add Self-Signed CA as Trusted in iOS App

In your iOS app, you'll need to add the self-signed CA as trusted when making HTTPS requests.

In order to do that, we need to handle URLAuthenticationChallenge in URLSessionDelegate.

import Foundation

class CustomURLSessionDelegate: NSObject, URLSessionDelegate {
	let cert = """
	-----BEGIN CERTIFICATE-----
	Paste your CA .pem certificate here (ca/certs/ca.cert.pem)
	-----END CERTIFICATE-----
	"""

	private func createSecCertificateFromPEMString(pemString: String) -> SecCertificate? {
		let base64Encoded = pemString
			.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "")
			.replacingOccurrences(of: "-----END CERTIFICATE-----", with: "")
			.replacingOccurrences(of: "\n", with: "")
			.replacingOccurrences(of: "\r", with: "")
			.replacingOccurrences(of: " ", with: "")

		guard let decodedData = Data(base64Encoded: base64Encoded) else {
			print("Failed to decode base64 string")
			return nil
		}
		// Create a SecCertificate from the Data
		guard let certificate = SecCertificateCreateWithData(nil, decodedData as CFData) else {
			print("Failed to create SecCertificate from data")
			return nil
		}
		return certificate
	}

	func urlSession(_ session: URLSession,
				didReceive challenge: URLAuthenticationChallenge,
				completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
		guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust else {
			return completionHandler(.performDefaultHandling, nil)
		}
        let serverTrust = challenge.protectionSpace.serverTrust else {
            return completionHandler(.performDefaultHandling, nil)
        }
		guard let customCARootCert = createSecCertificateFromPEMString(pemString: cert) else {
			return completionHandler(.performDefaultHandling, nil)
		}
		SecTrustSetAnchorCertificates(serverTrust, [customCARootCert] as CFArray)
		SecTrustSetAnchorCertificatesOnly(serverTrust, false)
		completionHandler(.performDefaultHandling, nil)
	}
}

// Usage
let delegate = CustomURLSessionDelegate()
let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)

Disable App Transport Security (ATS)

The final step is to disable App Transport Security (ATS). ATS is a security feature introduced in iOS 9, which enforces best practices for secure network communication by default.

ATS requires apps to communicate using HTTPS and secure TLS protocols. By default, ATS does not trust self-signed certificates.

To work with self-signed certificates in your app, you'll need to update your app's Info.plist.

<key>NSAppTransportSecurity</key>
<dict>
	<key>NSAllowsArbitraryLoads</key>
	<true/>
</dict>

This configuration allows you to work with self-signed certificates. Now your app can handle https requests signed with our custom CA without installing CA’s root certificate on your client devices.

You are done!

Handling self-signed certificates in Swift can be a bit tricky, but it's a valuable technique for securing your intranet API environment.

By following this step-by-step guide, you can efficiently work with self-signed certificates in your iOS app and ensure a seamless transition to production with trusted CA-issued certificates.


The lead image for this article was generated by HackerNoon's AI Image Generator via the prompt "ios app".


Written by micci | With a strong work ethic and a lifelong love of technology, I strive to make a positive impact through my work
Published by HackerNoon on 2023/05/09