From 79409e8a52a9d3f5153053be8eab92b31e7f8292 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 15 Aug 2022 20:21:16 +0100
Subject: [PATCH] Implement certificate pinning for report requests

---
 Sources/ReportingFeature/SendReport.swift | 34 +++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/Sources/ReportingFeature/SendReport.swift b/Sources/ReportingFeature/SendReport.swift
index 41c6f159..e79214dd 100644
--- a/Sources/ReportingFeature/SendReport.swift
+++ b/Sources/ReportingFeature/SendReport.swift
@@ -45,6 +45,36 @@ extension SendReport {
     )
 }
 
-private class SessionDelegate: NSObject, URLSessionDelegate {
-    // TODO: handle TLS
+private final class SessionDelegate: NSObject, URLSessionDelegate {
+    func urlSession(
+        _ session: URLSession,
+        didReceive challenge: URLAuthenticationChallenge,
+        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
+    ) {
+        let authenticationMethod = challenge.protectionSpace.authenticationMethod
+        if authenticationMethod == NSURLAuthenticationMethodServerTrust,
+           let serverTrust = challenge.protectionSpace.serverTrust,
+           handleServerTrustChallenge(serverTrust) {
+            completionHandler(.useCredential, URLCredential(trust: serverTrust))
+            return
+        }
+        completionHandler(.cancelAuthenticationChallenge, nil)
+    }
+}
+
+private func handleServerTrustChallenge(_ serverTrust: SecTrust) -> Bool {
+    guard let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
+        return false
+    }
+
+    let serverCertCFData = SecCertificateCopyData(serverCert)
+    let serverCertNSData = NSData(
+        bytes: CFDataGetBytePtr(serverCertCFData),
+        length: CFDataGetLength(serverCertCFData)
+    )
+
+    let localCertPath = Bundle.module.path(forResource: "report_cert", ofType: "crt")!
+    let localCertNSData = NSData(contentsOfFile: localCertPath)!
+
+    return serverCertNSData.isEqual(to: localCertNSData as Data)
 }
-- 
GitLab