Skip to content

Instantly share code, notes, and snippets.

@AKosmachyov
Last active October 18, 2024 18:15
Show Gist options
  • Save AKosmachyov/879c99f1525901837d87a16ed48cc714 to your computer and use it in GitHub Desktop.
Save AKosmachyov/879c99f1525901837d87a16ed48cc714 to your computer and use it in GitHub Desktop.
  1. Create file san.cnf
[ req ]
default_bits        = 2048
distinguished_name  = req_distinguished_name
req_extensions      = SAN
extensions          = SAN
[ req_distinguished_name ]
countryName         = BY
stateOrProvinceName = Minsk
localityName        = Minsk
organizationName    = Alex
[SAN]
subjectAltName      = IP:192.168.31.120
extendedKeyUsage    = serverAuth
basicConstraints    = CA:TRUE,pathlen:0
  1. Generate crt and key files
openssl req \
    -newkey rsa:2048 \
    -x509 \
    -nodes \
    -keyout myKey.key \
    -new \
    -out myCert.crt \
    -subj /CN=192.168.31.120 \
    -config ./san.cnf \
    -reqexts SAN \
    -extensions SAN \
    -sha256 \
    -days 365
  1. Install .crt file on iOS
  2. Open & Install: Settings -> Profile Downloaded -> Install
  3. Enable certificate: General -> About -> Certificate Trust Settings
  4. Example of NodeJS server
var https = require('https');
var fs = require('fs');

const options = {
    key: fs.readFileSync('./myKey.key'),
    cert: fs.readFileSync('./myCert.crt')
};  

https.createServer(options, function(request, response) {
    response.setHeader('Content-Type', 'application/json');
    response.writeHead(200);
    response.end('{"test": 1}');
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
// Mark: - Add delegate for URLSession
let taskDelegateMonitor = TaskDelegateMonitor()
let session = URLSession(configuration: .default, delegate: taskDelegateMonitor, delegateQueue: nil)
let task = session.dataTask(with: request) { (data, response, error) in
if let error,
let urlError = error as? URLError
{
switch urlError.code {
case .serverCertificateUntrusted:
break
}
}
}
// Mark: - Saving certificate
let url = FileManager.default.temporaryDirectory.appendingPathComponent("certificate.crt")
if let certText = TQManifest.shared.taskDelegateMonitor.currentServerCertificate {
try? certText.write(to: url, atomically: true, encoding: .utf8)
}
let docController = UIDocumentPickerViewController(forExporting: [url])
present(docController, animated: true, completion: nil)
// Mark: - Monitor
class TaskDelegateMonitor: NSObject, URLSessionTaskDelegate {
public private(set) var currentServerCertificate: String?
private var host = ""
public func urlSession(
_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
defer {
completionHandler(.performDefaultHandling, nil)
}
let protectionSpace = challenge.protectionSpace
guard let trust = protectionSpace.serverTrust,
protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
host != protectionSpace.host
else { return }
guard let serverCertificate = SecTrustGetCertificateAtIndex(trust, 0) else { return }
let serverCertificateData = SecCertificateCopyData(serverCertificate)
let data = CFDataGetBytePtr(serverCertificateData)
let size = CFDataGetLength(serverCertificateData)
let certificate = Data(bytes: data!, count: size)
var textContent = "-----BEGIN CERTIFICATE-----\n"
textContent += certificate.base64EncodedString() + "\n"
textContent += "-----END CERTIFICATE-----"
currentServerCertificate = textContent
host = protectionSpace.host
}
}
@AKosmachyov
Copy link
Author

Requirements for trusted certificates in iOS 13 and macOS 10.15 - https://support.apple.com/en-us/103769

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment