diff --git a/SecureEnclaveToken.xcodeproj/project.pbxproj b/SecureEnclaveToken.xcodeproj/project.pbxproj
index fa738b9..02b7e5e 100644
--- a/SecureEnclaveToken.xcodeproj/project.pbxproj
+++ b/SecureEnclaveToken.xcodeproj/project.pbxproj
@@ -439,6 +439,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
+ MARKETING_VERSION = 1.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.mwielgoszewski.SecureEnclaveToken;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
@@ -468,6 +469,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
+ MARKETING_VERSION = 1.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.mwielgoszewski.SecureEnclaveToken;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
@@ -488,6 +490,7 @@
"@executable_path/../Frameworks",
"@executable_path/../../../../Frameworks",
);
+ MARKETING_VERSION = 1.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.mwielgoszewski.SecureEnclaveToken.SecureEnclaveTokenExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -509,6 +512,7 @@
"@executable_path/../Frameworks",
"@executable_path/../../../../Frameworks",
);
+ MARKETING_VERSION = 1.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.mwielgoszewski.SecureEnclaveToken.SecureEnclaveTokenExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
diff --git a/SecureEnclaveToken/ContentView.swift b/SecureEnclaveToken/ContentView.swift
index 363b2ca..e7ad71f 100644
--- a/SecureEnclaveToken/ContentView.swift
+++ b/SecureEnclaveToken/ContentView.swift
@@ -12,8 +12,10 @@ import CertificateSigningRequest
struct ContentView: View {
@State private var keysIsEmpty = false
- @State private var loadButton = "Query Token Configuration"
+ @State private var loadButton = "Query Token"
@State private var keysLoaded = 0
+ @State private var certificateLabel = ""
+ @State private var keyLabel = ""
@State private var generateKeyDescription = ""
@State private var showDeleteConfirmation = false
@State private var commonName = ""
@@ -76,7 +78,6 @@ struct ContentView: View {
var body: some View {
let tag = "com.mwielgoszewski.SecureEnclaveToken.Key".data(using: .utf8)!
- var keysLoaded = tokenConfig.keychainItems.count
VStack(alignment: .leading, spacing: 5) {
HStack {
@@ -90,16 +91,33 @@ struct ContentView: View {
let certificate = panel.url!.absoluteURL
_ = loadCertificateForTagIntoTokenConfig(certificatePath: certificate, tag: tag, tokenConfig: tokenConfig)
}
- } else if self.loadButton == "Unload SE Keys" {
+ } else if self.loadButton == "Unload Token" {
tokenConfig.keychainItems.removeAll()
}
- self.loadButton = tokenConfig.keychainItems.isEmpty ? "Load SE Keys" : "Unload SE Keys"
+ self.loadButton = tokenConfig.keychainItems.isEmpty ? "Load Token" : "Unload Token"
keysLoaded = tokenConfig.keychainItems.count
+ if keysLoaded > 0 {
+ do {
+ let tkcert = try tokenConfig.certificate(for: tag)
+ let tkkey = try tokenConfig.key(for: tag)
+ certificateLabel = " • \(tkcert.label ?? "")"
+ keyLabel = " • \(tkkey.label ?? "")"
+ } catch {
+ }
+ } else {
+ certificateLabel = ""
+ keyLabel = ""
+ }
+
}) {
Text(loadButton)
}
- Text("\(keysLoaded) token keychain items loaded")
+ VStack(alignment: .leading) {
+ Text("\(keysLoaded) token keychain items loaded")
+ Text(certificateLabel)
+ Text(keyLabel)
+ }
}
HStack(alignment: .top) {
diff --git a/SecureEnclaveToken/Info.plist b/SecureEnclaveToken/Info.plist
index 8aa8d09..ef05b5d 100644
--- a/SecureEnclaveToken/Info.plist
+++ b/SecureEnclaveToken/Info.plist
@@ -17,13 +17,15 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.0
+ $(MARKETING_VERSION)
CFBundleVersion
1
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
+ NSHumanReadableCopyright
+ Marcin Wielgoszewski
NSMainStoryboardFile
Main
NSPrincipalClass
diff --git a/SecureEnclaveToken/SecureEnclaveTokenUtils.swift b/SecureEnclaveToken/SecureEnclaveTokenUtils.swift
index 4e9d7ea..35cec4c 100644
--- a/SecureEnclaveToken/SecureEnclaveTokenUtils.swift
+++ b/SecureEnclaveToken/SecureEnclaveTokenUtils.swift
@@ -7,6 +7,7 @@
import Foundation
import Security
+import CryptoKit
import CryptoTokenKit
func generateKeyInEnclave(tag: Data, accessibility: CFString, accessControlFlags: Int) -> SecKey {
@@ -95,7 +96,7 @@ func deleteSecureEnclaveKey(tag: Data) -> Bool {
return status == errSecSuccess
}
-func loadCertificateForTagIntoTokenConfig(certificatePath: URL, tag: Data, tokenConfig: TKToken.Configuration) -> Bool {
+func loadCertificateForTagIntoTokenConfig(certificatePath: URL, tag: Data, tokenConfig: TKToken.Configuration) -> SecCertificate? {
if FileManager.default.fileExists(atPath: certificatePath.path) {
do {
@@ -122,27 +123,36 @@ func loadCertificateForTagIntoTokenConfig(certificatePath: URL, tag: Data, token
throw NSError()
}
+ let publicKeyHash = Insecure.SHA1.hash(data: bytes)
+
+ var commonName: CFString?
+ _ = SecCertificateCopyCommonName(certificate, &commonName)
+
let tokenCertificate = TKTokenKeychainCertificate(certificate: certificate, objectID: tag)
- tokenCertificate?.label = "se certificate"
+ tokenCertificate?.label = "Certificate for PIV Authentication (\(commonName ?? "Secure Enclave" as CFString))"
let tokenKey = TKTokenKeychainKey(certificate: certificate, objectID: tag)
- tokenKey?.label = "se key"
+ tokenKey?.label = "PIV AUTH key"
tokenKey?.canSign = true
tokenKey?.canPerformKeyExchange = true
tokenKey?.isSuitableForLogin = true
tokenKey?.canDecrypt = false
+ tokenKey?.applicationTag = tag
+ tokenKey?.keySizeInBits = 256
+ tokenKey?.keyType = kSecAttrKeyTypeECSECPrimeRandom as String
+ tokenKey?.publicKeyData = bytes
+ tokenKey?.publicKeyHash = publicKeyHash.data
tokenConfig.keychainItems.append(tokenKey!)
tokenConfig.keychainItems.append(tokenCertificate!)
- return true
+ return certificate
} catch {
print("Failed to create cert??")
- return false
}
} else {
print("Certificate is not a file")
}
- return false
+ return nil
}
func importCertificateAndCreateSecIdentity(key: SecKey, certificatePath: URL, tag: Data) -> SecIdentity? {
diff --git a/SecureEnclaveTokenExtension/Info.plist b/SecureEnclaveTokenExtension/Info.plist
index 18e69c1..c678d8e 100644
--- a/SecureEnclaveTokenExtension/Info.plist
+++ b/SecureEnclaveTokenExtension/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.0
+ $(MARKETING_VERSION)
CFBundleVersion
1
LSMinimumSystemVersion
diff --git a/SecureEnclaveTokenExtension/Token.swift b/SecureEnclaveTokenExtension/Token.swift
index 758685e..8a3d91f 100644
--- a/SecureEnclaveTokenExtension/Token.swift
+++ b/SecureEnclaveTokenExtension/Token.swift
@@ -14,6 +14,13 @@ class Token: TKSmartCardToken, TKTokenDelegate {
NSLog("Got instanceID: \(configuration.instanceID)")
super.init(smartCard: smartCard, aid: nil, instanceID: configuration.instanceID, tokenDriver: tokenDriver)
self.keychainContents?.fill(with: configuration.keychainItems)
+ do {
+ let tag = "com.mwielgoszewski.SecureEnclaveToken.Key".data(using: .utf8)!
+ let certificate = try self.keychainContents?.certificate(forObjectID: tag)
+ NSLog("Got certificate for \(String(describing: certificate?.label)) -> \(String(describing: certificate?.data.base64EncodedString()))")
+ } catch {
+ NSLog("Failed pulling certificate")
+ }
NSLog("Got keychain items: \(String(describing: self.keychainContents?.items.count))")
}
diff --git a/SecureEnclaveTokenExtension/TokenDriver.swift b/SecureEnclaveTokenExtension/TokenDriver.swift
index 6dd49d0..c5dadc7 100644
--- a/SecureEnclaveTokenExtension/TokenDriver.swift
+++ b/SecureEnclaveTokenExtension/TokenDriver.swift
@@ -18,5 +18,4 @@ class TokenDriver: TKSmartCardTokenDriver, TKSmartCardTokenDriverDelegate {
func tokenDriver(_ driver: TKSmartCardTokenDriver, createTokenFor smartCard: TKSmartCard, aid AID: Data?) throws -> TKSmartCardToken {
return try Token(smartCard: smartCard, aid: AID, tokenDriver: self)
}
-
}
diff --git a/SecureEnclaveTokenExtension/TokenSession.swift b/SecureEnclaveTokenExtension/TokenSession.swift
index c65e619..9300fdd 100644
--- a/SecureEnclaveTokenExtension/TokenSession.swift
+++ b/SecureEnclaveTokenExtension/TokenSession.swift
@@ -17,114 +17,85 @@ class TokenSession: TKSmartCardTokenSession, TKTokenSessionDelegate {
func tokenSession(_ session: TKTokenSession, supports operation: TKTokenOperation, keyObjectID: Any, algorithm: TKTokenKeyAlgorithm) -> Bool {
// Indicate whether the given key supports the specified operation and algorithm.
- NSLog("Determining if \(keyObjectID) supports \(operation.rawValue)")
- do {
- let tokenKey = try self.token.keychainContents?.key(forObjectID: keyObjectID)
-
- switch operation {
- case .signData:
- NSLog("Checking if key can sign for algorithm \(algorithm)")
- if tokenKey!.canSign {
- if algorithm.isAlgorithm(.ecdsaSignatureRFC4754) {
- NSLog("Can sign ecdsaSignatureRFC4754")
- return true
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962) {
- NSLog("Can sign ecdsaSignatureDigestX962")
- return true
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA1) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA1")
- return true
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA224) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA224")
- return true
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA256) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA256")
- return true
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA384) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA384")
- return true
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA512) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA512")
- return true
- }
- return false
- }
-
- case .performKeyExchange:
- NSLog("Checking if key can perform key exchange \(algorithm)")
- if tokenKey!.canPerformKeyExchange {
- return true
- }
-
- case .none:
- break
- case .readData:
- break
- case .decryptData:
- break
- @unknown default:
- NSLog("Unhandled token operation requested: \(operation.rawValue)")
- }
- } catch {
- NSLog("Could not find private key: \(keyObjectID)")
+ let tag = String(data: keyObjectID as! Data, encoding: .utf8)!
+
+ NSLog("Querying for keyObjectID: \(tag) to determine whether TKTokenOperation:\(operation.rawValue) is supported")
+
+ var item: CFTypeRef?
+ var privateKey: SecKey
+ let query: [String: Any] = [kSecClass as String: kSecClassKey,
+ kSecAttrApplicationTag as String: tag,
+ kSecAttrKeyType as String: kSecAttrKeyTypeEC,
+ kSecReturnRef as String: true]
+
+ let status = SecItemCopyMatching(query as CFDictionary, &item)
+ guard status == errSecSuccess else {
+ NSLog("Could not find private key with tag: \(tag)")
return false
}
- NSLog("Key \(keyObjectID) does not support operation: \(operation.rawValue)")
+ privateKey = (item as! SecKey)
+
+ guard let alg = tokenAlgorithmToSecKeyAlgorithm(algorithm) else {
+ return false
+ }
+
+ switch operation {
+ case .signData:
+ NSLog("Checking if keyObjectID: \(tag) can sign for algorithm \(alg.rawValue)")
+ return SecKeyIsAlgorithmSupported(privateKey, SecKeyOperationType.sign, alg)
+ case .performKeyExchange:
+ NSLog("Checking if keyObjectID: \(tag) can perform key exchange \(alg.rawValue)")
+ return SecKeyIsAlgorithmSupported(privateKey, SecKeyOperationType.keyExchange, alg)
+ case .none:
+ break
+ case .readData:
+ break
+ case .decryptData:
+ NSLog("Checking if keyObjectID: \(tag) can decrypt for algorithm \(alg.rawValue)")
+ return SecKeyIsAlgorithmSupported(privateKey, SecKeyOperationType.decrypt, alg)
+ @unknown default:
+ NSLog("Unhandled token operation requested: \(operation.rawValue)")
+ }
+
+ NSLog("Key \(tag) does not support operation: \(operation.rawValue)")
return false
}
func tokenSession(_ session: TKTokenSession, sign dataToSign: Data, keyObjectID: Any, algorithm: TKTokenKeyAlgorithm) throws -> Data {
- var signature: Data?
- var item: CFTypeRef?
- var privateKey: SecKey
+ let tag = String(data: keyObjectID as! Data, encoding: .utf8)!
- NSLog("Querying for key \(keyObjectID)")
+ guard let alg = tokenAlgorithmToSecKeyAlgorithm(algorithm) else {
+ throw NSError(domain: TKErrorDomain, code: TKError.Code.badParameter.rawValue, userInfo: nil)
+ }
+
+ NSLog("Querying for keyObjectID: \(tag) to sign \(dataToSign) with \(alg.rawValue)")
+ var item: CFTypeRef?
+ var privateKey: SecKey
let query: [String: Any] = [kSecClass as String: kSecClassKey,
- kSecAttrApplicationTag as String: keyObjectID,
+ kSecAttrApplicationTag as String: tag,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnRef as String: true]
let status = SecItemCopyMatching(query as CFDictionary, &item)
-
- if status == errSecSuccess {
- privateKey = (item as! SecKey)
- var error: Unmanaged?
- var alg: SecKeyAlgorithm = .ecdsaSignatureDigestX962
-
- if algorithm.isAlgorithm(.ecdsaSignatureRFC4754) {
- alg = .ecdsaSignatureRFC4754
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962) {
- NSLog("Can sign ecdsaSignatureDigestX962")
- alg = .ecdsaSignatureDigestX962
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA1) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA1")
- alg = .ecdsaSignatureDigestX962SHA1
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA224) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA224")
- alg = .ecdsaSignatureDigestX962SHA224
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA256) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA256")
- alg = .ecdsaSignatureDigestX962SHA256
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA384) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA384")
- alg = .ecdsaSignatureDigestX962SHA384
- } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA512) {
- NSLog("Can sign ecdsaSignatureDigestX962SHA512")
- alg = .ecdsaSignatureDigestX962SHA512
- }
-
- signature = SecKeyCreateSignature(privateKey,
- alg,
- dataToSign as CFData,
- &error) as Data?
- return signature!
- } else {
+ guard status == errSecSuccess else {
// If the operation failed for some reason, fill in an appropriate error like objectNotFound, corruptedData, etc.
// Note that responding with TKErrorCodeAuthenticationNeeded will trigger user authentication after which the current operation will be re-attempted.
throw NSError(domain: TKErrorDomain, code: TKError.Code.objectNotFound.rawValue, userInfo: nil)
}
+
+ privateKey = (item as! SecKey)
+
+ var error: Unmanaged?
+ guard let signature = SecKeyCreateSignature(privateKey,
+ alg,
+ dataToSign as CFData,
+ &error) as Data? else {
+ throw error!.takeRetainedValue() as Error
+ }
+
+ return signature
}
func tokenSession(_ session: TKTokenSession, decrypt ciphertext: Data, keyObjectID: Any, algorithm: TKTokenKeyAlgorithm) throws -> Data {
@@ -132,35 +103,96 @@ class TokenSession: TKSmartCardTokenSession, TKTokenSessionDelegate {
}
func tokenSession(_ session: TKTokenSession, performKeyExchange otherPartyPublicKeyData: Data, keyObjectID objectID: Any, algorithm: TKTokenKeyAlgorithm, parameters: TKTokenKeyExchangeParameters) throws -> Data {
- var secret: Data?
+
+ let tag = String(data: objectID as! Data, encoding: .utf8)!
+
+ NSLog("Querying for keyObjectID: \(tag) to perform key exchange")
var item: CFTypeRef?
var privateKey: SecKey
-
let query: [String: Any] = [kSecClass as String: kSecClassKey,
- kSecAttrApplicationTag as String: objectID,
+ kSecAttrApplicationTag as String: tag,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnRef as String: true]
let status = SecItemCopyMatching(query as CFDictionary, &item)
+ guard status == errSecSuccess else {
+ // If the operation failed for some reason, fill in an appropriate error like objectNotFound, corruptedData, etc.
+ // Note that responding with TKErrorCodeAuthenticationNeeded will trigger user authentication after which the current operation will be re-attempted.
+ throw NSError(domain: TKErrorDomain, code: TKError.Code.objectNotFound.rawValue, userInfo: nil)
+ }
- if status == errSecSuccess {
- privateKey = (item as! SecKey)
- var error: Unmanaged?
-
- let attributes: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
- kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
- kSecAttrKeySizeInBits as String: 256]
+ privateKey = (item as! SecKey)
- let publicKey = SecKeyCreateWithData(otherPartyPublicKeyData as CFData, attributes as CFDictionary, &error)!
+ let attributes: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
+ kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
+ kSecAttrKeySizeInBits as String: 256]
- secret = SecKeyCopyKeyExchangeResult(privateKey, SecKeyAlgorithm.ecdhKeyExchangeStandard, publicKey, parameters as! CFDictionary, &error) as Data?
- return secret!
+ var error: Unmanaged?
+ guard let publicKey = SecKeyCreateWithData(otherPartyPublicKeyData as CFData,
+ attributes as CFDictionary,
+ &error) else {
+ throw error!.takeRetainedValue() as Error
+ }
- } else {
- // If the operation failed for some reason, fill in an appropriate error like objectNotFound, corruptedData, etc.
- // Note that responding with TKErrorCodeAuthenticationNeeded will trigger user authentication after which the current operation will be re-attempted.
+ guard let kexAlg = tokenAlgorithmToSecKeyAlgorithm(algorithm) else {
throw NSError(domain: TKErrorDomain, code: TKError.Code.badParameter.rawValue, userInfo: nil)
}
+
+ guard let secret = SecKeyCopyKeyExchangeResult(privateKey,
+ kexAlg,
+ publicKey,
+ parameters as! CFDictionary,
+ &error) as Data? else {
+ throw error!.takeRetainedValue() as Error
+ }
+ return secret
}
+
+ private func tokenAlgorithmToSecKeyAlgorithm(_ algorithm: TKTokenKeyAlgorithm) -> SecKeyAlgorithm? {
+
+ if algorithm.isAlgorithm(.ecdsaSignatureRFC4754) {
+ return .ecdsaSignatureRFC4754
+ } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962) {
+ return .ecdsaSignatureDigestX962
+ } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA1) {
+ return .ecdsaSignatureDigestX962SHA1
+ } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA224) {
+ return .ecdsaSignatureDigestX962SHA224
+ } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA256) {
+ return .ecdsaSignatureDigestX962SHA256
+ } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA384) {
+ return .ecdsaSignatureDigestX962SHA384
+ } else if algorithm.isAlgorithm(.ecdsaSignatureDigestX962SHA512) {
+ return .ecdsaSignatureDigestX962SHA512
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeStandard) {
+ return .ecdhKeyExchangeStandard
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeStandardX963SHA1) {
+ return .ecdhKeyExchangeStandardX963SHA1
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeStandardX963SHA224) {
+ return .ecdhKeyExchangeStandardX963SHA224
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeStandardX963SHA256) {
+ return .ecdhKeyExchangeStandardX963SHA256
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeStandardX963SHA384) {
+ return .ecdhKeyExchangeStandardX963SHA384
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeStandardX963SHA512) {
+ return .ecdhKeyExchangeStandardX963SHA512
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeCofactor) {
+ return .ecdhKeyExchangeCofactor
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeCofactorX963SHA1) {
+ return .ecdhKeyExchangeCofactorX963SHA1
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeCofactorX963SHA224) {
+ return .ecdhKeyExchangeCofactorX963SHA224
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeCofactorX963SHA256) {
+ return .ecdhKeyExchangeCofactorX963SHA256
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeCofactorX963SHA384) {
+ return .ecdhKeyExchangeCofactorX963SHA384
+ } else if algorithm.isAlgorithm(.ecdhKeyExchangeCofactorX963SHA512) {
+ return .ecdhKeyExchangeCofactorX963SHA512
+ }
+
+ return nil
+
+ }
+
}
diff --git a/images/SecureEnclaveToken.png b/images/SecureEnclaveToken.png
index 8b26745..2f28984 100644
Binary files a/images/SecureEnclaveToken.png and b/images/SecureEnclaveToken.png differ