]> git.ipfire.org Git - thirdparty/wireguard-apple.git/commitdiff
Model: migrate iOS 14 keychain references to iOS 15 format
authorJason A. Donenfeld <Jason@zx2c4.com>
Thu, 23 Sep 2021 04:00:14 +0000 (06:00 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Thu, 23 Sep 2021 04:11:19 +0000 (06:11 +0200)
Keychain references used to be bijective, but with the change in format,
Apple tried to be too clever, and references are no longer bijective.
This lead to us deleting keychain entries, which in turn emptied out
people's configs upon upgrading to iOS 15. Disaster!

Fix this by detecting the change in format and saving the new password
reference. We still rely on this being bijective moving forward;
hopefully this bug won't repeat itself. It would be nice to not rely on
that property, but doing so without grinding startup to a halt isn't
obviously done, given how slow the keychain accesses are and how limited
the API is.

Reported-by: Eddie <stunnel@attglobal.net>
Reported-by: Anatoli <me@anatoli.ws>
Reported-by: Alan Graham <alan@meshify.app>
Reported-by: Jacob Wilder <oss@jacobwilder.org>
Reported-by: Miguel Arroz <miguel.arroz@gmail.com>
Reported-by: Reid Rankin <reidrankin@gmail.com>
Reported-by: Fabien <patate.cosmique@pm.me>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Sources/Shared/Model/NETunnelProviderProtocol+Extension.swift

index 12b9d6bca11e0be0c63e097213455eaf7b5901e4..ecb6e1f2b953d0ec1cb2097851fc182b1dc6085b 100644 (file)
@@ -72,7 +72,7 @@ extension NETunnelProviderProtocol {
             #error("Unimplemented")
             #endif
             guard passwordReference == nil else { return true }
-            wg_log(.debug, message: "Migrating tunnel configuration '\(name)'")
+            wg_log(.info, message: "Migrating tunnel configuration '\(name)'")
             passwordReference = Keychain.makeReference(containing: oldConfig, called: name)
             return true
         }
@@ -81,6 +81,27 @@ extension NETunnelProviderProtocol {
             providerConfiguration = ["UID": getuid()]
             return true
         }
+        #elseif os(iOS)
+        if #available(iOS 15, *) {
+            /* Update the stored reference from the old iOS 14 one to the canonical iOS 15 one.
+             * The iOS 14 ones are 96 bits, while the iOS 15 ones are 160 bits. We do this so
+             * that we can have fast set exclusion in deleteReferences safely. */
+            if passwordReference != nil && passwordReference!.count == 12 {
+                var result: CFTypeRef?
+                let ret = SecItemCopyMatching([kSecValuePersistentRef: passwordReference!,
+                                               kSecReturnPersistentRef: true] as CFDictionary,
+                                               &result)
+                if ret != errSecSuccess || result == nil {
+                    return false
+                }
+                guard let newReference = result as? Data else { return false }
+                if !newReference.elementsEqual(passwordReference!) {
+                    wg_log(.info, message: "Migrating iOS 14-style keychain reference to iOS 15-style keychain reference for '\(name)'")
+                    passwordReference = newReference
+                    return true
+                }
+            }
+        }
         #endif
         return false
     }