summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2021-09-14 15:11:27 +0200
committerAndrej Mihajlov <and@mullvad.net>2021-09-14 15:11:27 +0200
commite553d10b869c46e7ab922b86c32f4bd016e4fdac (patch)
tree4a37a4a43ddbc936d1e87c4be55c8b5c23867952
parentc2be1a3bc1c6a89cad9f8198cd83f128c99bcca6 (diff)
parentc9c647e08c50c918f915e4bd9f206d54e0f11c24 (diff)
downloadmullvadvpn-e553d10b869c46e7ab922b86c32f4bd016e4fdac.tar.xz
mullvadvpn-e553d10b869c46e7ab922b86c32f4bd016e4fdac.zip
Merge branch 'remove-keychain-revision'
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj22
-rw-r--r--ios/MullvadVPN/Keychain/Keychain.swift (renamed from ios/MullvadVPN/Keychain.swift)0
-rw-r--r--ios/MullvadVPN/Keychain/KeychainAttributes.swift (renamed from ios/MullvadVPN/KeychainAttributes.swift)0
-rw-r--r--ios/MullvadVPN/Keychain/KeychainClass.swift (renamed from ios/MullvadVPN/KeychainClass.swift)0
-rw-r--r--ios/MullvadVPN/Keychain/KeychainError.swift (renamed from ios/MullvadVPN/KeychainError.swift)0
-rw-r--r--ios/MullvadVPN/Keychain/KeychainMatchLimit.swift (renamed from ios/MullvadVPN/KeychainMatchLimit.swift)0
-rw-r--r--ios/MullvadVPN/Keychain/KeychainReturn.swift (renamed from ios/MullvadVPN/KeychainReturn.swift)0
-rw-r--r--ios/MullvadVPN/KeychainItemRevision.swift70
-rw-r--r--ios/MullvadVPN/TunnelSettingsManager.swift95
9 files changed, 43 insertions, 144 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj
index 5f81d89189..ce72f88bb4 100644
--- a/ios/MullvadVPN.xcodeproj/project.pbxproj
+++ b/ios/MullvadVPN.xcodeproj/project.pbxproj
@@ -731,13 +731,7 @@
5840250022B1124600E4CFEC /* IPAddress+Codable.swift */,
5850366725A47AC700A43E93 /* IPAddressRange+Codable.swift */,
58561C98239A5D1500BD6B5E /* IPEndpoint.swift */,
- 58FAEDF6245088E100CB0F5B /* Keychain.swift */,
- 58FAEDEB245059F000CB0F5B /* KeychainAttributes.swift */,
- 58FAEE0024533A9C00CB0F5B /* KeychainClass.swift */,
- 58AEEF642344A36000C9BBD5 /* KeychainError.swift */,
- 58F840AE2464382C0044E708 /* KeychainItemRevision.swift */,
- 58FAEDFC24533A5500CB0F5B /* KeychainMatchLimit.swift */,
- 58FAEDFE24533A7000CB0F5B /* KeychainReturn.swift */,
+ 58FB865626E8C06800F188BC /* Keychain */,
58727282265D173C00F315B2 /* LaunchScreen.storyboard */,
58A1AA8623F43901009F7EA6 /* Location.swift */,
583DA21325FA4B5C00318683 /* LocationDataSource.swift */,
@@ -857,6 +851,19 @@
path = Assets;
sourceTree = "<group>";
};
+ 58FB865626E8C06800F188BC /* Keychain */ = {
+ isa = PBXGroup;
+ children = (
+ 58FAEDF6245088E100CB0F5B /* Keychain.swift */,
+ 58FAEDEB245059F000CB0F5B /* KeychainAttributes.swift */,
+ 58FAEE0024533A9C00CB0F5B /* KeychainClass.swift */,
+ 58AEEF642344A36000C9BBD5 /* KeychainError.swift */,
+ 58FAEDFC24533A5500CB0F5B /* KeychainMatchLimit.swift */,
+ 58FAEDFE24533A7000CB0F5B /* KeychainReturn.swift */,
+ );
+ path = Keychain;
+ sourceTree = "<group>";
+ };
/* End PBXGroup section */
/* Begin PBXLegacyTarget section */
@@ -1298,6 +1305,7 @@
58B93A1826C54D7E00A55733 /* Locking.swift in Sources */,
58FAEE0224533ABB00CB0F5B /* KeychainMatchLimit.swift in Sources */,
5860392A26DCE7AB00554C79 /* PromiseCompletion.swift in Sources */,
+ 58FAEE0224533ABB00CB0F5B /* KeychainMatchLimit.swift in Sources */,
58FAEE0324533ABE00CB0F5B /* KeychainReturn.swift in Sources */,
58BFA5CD22A7CE1F00A6173D /* ApplicationConfiguration.swift in Sources */,
5850368D25A49E2200A43E93 /* PrivateKeyWithMetadata.swift in Sources */,
diff --git a/ios/MullvadVPN/Keychain.swift b/ios/MullvadVPN/Keychain/Keychain.swift
index 383219990a..383219990a 100644
--- a/ios/MullvadVPN/Keychain.swift
+++ b/ios/MullvadVPN/Keychain/Keychain.swift
diff --git a/ios/MullvadVPN/KeychainAttributes.swift b/ios/MullvadVPN/Keychain/KeychainAttributes.swift
index 397620f37b..397620f37b 100644
--- a/ios/MullvadVPN/KeychainAttributes.swift
+++ b/ios/MullvadVPN/Keychain/KeychainAttributes.swift
diff --git a/ios/MullvadVPN/KeychainClass.swift b/ios/MullvadVPN/Keychain/KeychainClass.swift
index 86e13f2bd6..86e13f2bd6 100644
--- a/ios/MullvadVPN/KeychainClass.swift
+++ b/ios/MullvadVPN/Keychain/KeychainClass.swift
diff --git a/ios/MullvadVPN/KeychainError.swift b/ios/MullvadVPN/Keychain/KeychainError.swift
index 4758d08b66..4758d08b66 100644
--- a/ios/MullvadVPN/KeychainError.swift
+++ b/ios/MullvadVPN/Keychain/KeychainError.swift
diff --git a/ios/MullvadVPN/KeychainMatchLimit.swift b/ios/MullvadVPN/Keychain/KeychainMatchLimit.swift
index f86b010532..f86b010532 100644
--- a/ios/MullvadVPN/KeychainMatchLimit.swift
+++ b/ios/MullvadVPN/Keychain/KeychainMatchLimit.swift
diff --git a/ios/MullvadVPN/KeychainReturn.swift b/ios/MullvadVPN/Keychain/KeychainReturn.swift
index 7216ffbd80..7216ffbd80 100644
--- a/ios/MullvadVPN/KeychainReturn.swift
+++ b/ios/MullvadVPN/Keychain/KeychainReturn.swift
diff --git a/ios/MullvadVPN/KeychainItemRevision.swift b/ios/MullvadVPN/KeychainItemRevision.swift
deleted file mode 100644
index 6e73d1a6a8..0000000000
--- a/ios/MullvadVPN/KeychainItemRevision.swift
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// KeychainItemRevision.swift
-// MullvadVPN
-//
-// Created by pronebird on 07/05/2020.
-// Copyright © 2020 Mullvad VPN AB. All rights reserved.
-//
-
-import Foundation
-
-/// A struct that helps to organize revisions for Keychain items
-/// Uses `Keychain.Attributes.generic` field for storing `Int64` revision number.
-struct KeychainItemRevision {
- let revision: Int64
-
- /// Returns the `KeychainItemRevision` initialized with the next in sequence revision
- var nextRevision: KeychainItemRevision {
- return .init(revision: revision + 1)
- }
-
- /// Initialize a struct with the given revision number
- init(revision: Int64) {
- self.revision = revision
- }
-
- /// Initialize a struct from the given `Keychain.Attributes`
- ///
- /// Returns `nil` when `Keychain.Attributes.generic` is `nil` or when it's set to data that
- /// cannot be interpreted as `Int64`
- init?(attributes: Keychain.Attributes) {
- let revision = attributes.generic.flatMap { Self.parseRevision(from: $0) }
- if let revision = revision {
- self.revision = revision
- } else {
- return nil
- }
- }
-
- /// Store the revision number in the given `Keychain.Attributes`
- func store(in attributes: inout Keychain.Attributes) {
- attributes.generic = asData()
- }
-
- /// A convenience method to initialize the first revision in sequence
- static func firstRevision() -> Self {
- return .init(revision: 1)
- }
-
- /// Serialize the revision number as `Data`
- private func asData() -> Data {
- return withUnsafeBytes(of: revision) { Data($0) }
- }
-
- /// Private helper to parse `Data` into `Int64`
- /// Returns `nil` if the given raw data does not match the size of `Int64`
- private static func parseRevision(from rawData: Data) -> Int64? {
- var value: Int64 = 0
-
- // Ensure that the buffer has as many bytes as needed to fill the `Int64`
- guard rawData.count == MemoryLayout.size(ofValue: value) else {
- return nil
- }
-
- _ = withUnsafeMutableBytes(of: &value) { (valuePointer) in
- rawData.copyBytes(to: valuePointer)
- }
-
- return value
- }
-}
diff --git a/ios/MullvadVPN/TunnelSettingsManager.swift b/ios/MullvadVPN/TunnelSettingsManager.swift
index aaf5453f1b..25bf72c41f 100644
--- a/ios/MullvadVPN/TunnelSettingsManager.swift
+++ b/ios/MullvadVPN/TunnelSettingsManager.swift
@@ -12,9 +12,6 @@ import Security
/// Service name used for keychain items
private let kServiceName = "Mullvad VPN"
-/// Maximum number of attempts to perform when updating the Keychain entry "atomically"
-private let kMaxAtomicUpdateRetryLimit = 20
-
enum TunnelSettingsManager {}
extension TunnelSettingsManager {
@@ -32,9 +29,6 @@ extension TunnelSettingsManager {
/// A failure to update the existing entry in Keychain
case updateEntry(Keychain.Error)
- /// A failure to atomically update a Keychain entry after multiple attempts
- case updateEntryAtomicallyRetryLimitExceeded
-
/// A failure to remove an entry in Keychain
case removeEntry(Keychain.Error)
@@ -106,9 +100,6 @@ extension TunnelSettingsManager {
// Store value
attributes.valueData = data
- // Add revision
- KeychainItemRevision.firstRevision().store(in: &attributes)
-
return Keychain.add(attributes)
.mapError { .addEntry($0) }
.map { _ in () }
@@ -136,11 +127,6 @@ extension TunnelSettingsManager {
let searchAttributes = searchTerm.makeKeychainAttributes()
var updateAttributes = Keychain.Attributes()
- // Add revision if it's missing
- if KeychainItemRevision(attributes: itemAttributes) == nil {
- KeychainItemRevision.firstRevision().store(in: &updateAttributes)
- }
-
// Fix the accessibility permission for the Keychain entry
if itemAttributes.accessible != Self.keychainAccessibleLevel {
updateAttributes.accessible = Self.keychainAccessibleLevel
@@ -163,68 +149,43 @@ extension TunnelSettingsManager {
/// The given block may run multiple times if Keychain entry was changed between read and write
/// operations.
static func update(searchTerm: KeychainSearchTerm,
- using changeConfiguration: (inout TunnelSettings) -> Void)
- -> Result<TunnelSettings>
+ using changeConfiguration: (inout TunnelSettings) -> Void) -> Result<TunnelSettings>
{
- for _ in (0 ..< kMaxAtomicUpdateRetryLimit) {
- var searchQuery = searchTerm.makeKeychainAttributes()
- searchQuery.return = [.attributes, .data]
-
- let result = Keychain.findFirst(query: searchQuery)
- .mapError { .lookupEntry($0) }
- .flatMap { (itemAttributes) -> Result<TunnelSettings> in
- let itemAttributes = itemAttributes!
- let serializedData = itemAttributes.valueData!
- let account = itemAttributes.account!
-
- // Parse the current revision from Keychain attributes
- let currentRevision = KeychainItemRevision(attributes: itemAttributes)
+ var searchQuery = searchTerm.makeKeychainAttributes()
+ searchQuery.return = [.attributes, .data]
- // Pick the next revision in sequence
- let nextRevision = currentRevision?.nextRevision
- ?? KeychainItemRevision.firstRevision()
-
- return Self.decode(data: serializedData)
- .flatMap { (tunnelConfig) -> Result<TunnelSettings> in
- var tunnelConfig = tunnelConfig
- changeConfiguration(&tunnelConfig)
-
- return Self.encode(tunnelConfig: tunnelConfig)
- .flatMap { (newData) -> Result<TunnelSettings> in
- // `SecItemUpdate` does not accept query parameters when using
- // persistent reference, so constraint the query to account
- // token instead now when we know it
- var updateQuery = KeychainSearchTerm
- .accountToken(account)
- .makeKeychainAttributes()
+ let result = Keychain.findFirst(query: searchQuery)
+ .mapError { .lookupEntry($0) }
+ .flatMap { (itemAttributes) -> Result<TunnelSettings> in
+ let itemAttributes = itemAttributes!
+ let serializedData = itemAttributes.valueData!
+ let account = itemAttributes.account!
- // Provide the last known revision via generic field to prevent
- // overwriting the item if it was modified in the meanwhile.
- // This field can be missing for the existing apps on AppStore
- currentRevision?.store(in: &updateQuery)
+ return Self.decode(data: serializedData)
+ .flatMap { (tunnelConfig) -> Result<TunnelSettings> in
+ var tunnelConfig = tunnelConfig
+ changeConfiguration(&tunnelConfig)
- var updateAttributes = Keychain.Attributes()
- updateAttributes.valueData = newData
+ return Self.encode(tunnelConfig: tunnelConfig)
+ .flatMap { (newData) -> Result<TunnelSettings> in
+ // `SecItemUpdate` does not accept query parameters when using
+ // persistent reference, so constraint the query to account
+ // token instead now when we know it
+ let updateQuery = KeychainSearchTerm
+ .accountToken(account)
+ .makeKeychainAttributes()
- // Add the next revision number
- nextRevision.store(in: &updateAttributes)
+ var updateAttributes = Keychain.Attributes()
+ updateAttributes.valueData = newData
- return Keychain.update(query: updateQuery, update: updateAttributes)
- .mapError { .updateEntry($0) }
- .map { tunnelConfig }
+ return Keychain.update(query: updateQuery, update: updateAttributes)
+ .mapError { .updateEntry($0) }
+ .map { tunnelConfig }
}
- }
+ }
}
- // Retry if Keychain reported that the item was not found when updating
- if case .failure(.updateEntry(.itemNotFound)) = result {
- continue
- } else {
- return result
- }
- }
-
- return .failure(.updateEntryAtomicallyRetryLimitExceeded)
+ return result
}
static func remove(searchTerm: KeychainSearchTerm) -> Result<()> {