From 945907cfd4af3721a1f00887e13c813267681b48 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 8 Mar 2020 22:17:59 -0700 Subject: [PATCH 1/3] Supporting different EC sizes, RSA not working yet --- SecretAgent/Agent.swift | 27 +++++++++++++---- SecretKit/Common/Erasers/AnySecret.swift | 20 +++++++++++-- .../Common/OpenSSH/OpenSSHKeyWriter.swift | 29 ++++++++++++------- SecretKit/Secret.swift | 17 +++++++++++ .../SecureEnclave/SecureEnclaveSecret.swift | 2 ++ SecretKit/SmartCard/SmartCardSecret.swift | 2 ++ SecretKit/SmartCard/SmartCardStore.swift | 19 +++++++++--- Secretive/Preview Content/PreviewStore.swift | 2 ++ 8 files changed, 94 insertions(+), 24 deletions(-) diff --git a/SecretAgent/Agent.swift b/SecretAgent/Agent.swift index fa94204..617ebe8 100644 --- a/SecretAgent/Agent.swift +++ b/SecretAgent/Agent.swift @@ -65,7 +65,7 @@ extension Agent { for secret in secrets { let keyBlob = writer.data(secret: secret) keyData.append(writer.lengthAndData(of: keyBlob)) - let curveData = OpenSSHKeyWriter.Constants.curveType.data(using: .utf8)! + let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)! keyData.append(writer.lengthAndData(of: curveData)) } os_log(.debug, "Agent enumerated %@ identities", secrets.count as NSNumber) @@ -92,13 +92,28 @@ extension Agent { let derSignature = try store.sign(data: dataToSign, with: secret) // TODO: Move this notifier.notify(accessTo: secret) - let curveData = OpenSSHKeyWriter.Constants.curveType.data(using: .utf8)! + let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)! // Convert from DER formatted rep to raw (r||s) - let signature = try CryptoKit.P256.Signing.ECDSASignature(derRepresentation: derSignature) - let rawLength = signature.rawRepresentation.count/2 - let r = signature.rawRepresentation[0.. AnyHashable fileprivate let _name: () -> String + fileprivate let _algorithm: () -> Algorithm + fileprivate let _keySize: () -> Int fileprivate let _publicKey: () -> Data public init(_ secret: T) where T: Secret { @@ -14,26 +16,38 @@ public struct AnySecret: Secret { hashable = secret.hashable _id = secret._id _name = secret._name + _algorithm = secret._algorithm + _keySize = secret._keySize _publicKey = secret._publicKey } else { base = secret as Any self.hashable = secret _id = { secret.id as AnyHashable } _name = { secret.name } + _algorithm = { secret.algorithm } + _keySize = { secret.keySize } _publicKey = { secret.publicKey } } } public var id: AnyHashable { - return _id() + _id() } public var name: String { - return _name() + _name() + } + + public var algorithm: Algorithm { + _algorithm() + } + + public var keySize: Int { + _keySize() } public var publicKey: Data { - return _publicKey() + _publicKey() } public static func == (lhs: AnySecret, rhs: AnySecret) -> Bool { diff --git a/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift b/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift index c50f861..9d2a6a5 100644 --- a/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift +++ b/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift @@ -8,13 +8,13 @@ public struct OpenSSHKeyWriter { } public func data(secret: SecretType) -> Data { - lengthAndData(of: Constants.curveType.data(using: .utf8)!) + - lengthAndData(of: Constants.curveIdentifier.data(using: .utf8)!) + + lengthAndData(of: curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!) + + lengthAndData(of: curveIdentifier(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!) + lengthAndData(of: secret.publicKey) } public func openSSHString(secret: SecretType) -> String { - "\(Constants.curveType) \(data(secret: secret).base64EncodedString())" + "\(curveType(for: secret.algorithm, length: secret.keySize)) \(data(secret: secret).base64EncodedString())" } public func openSSHFingerprint(secret: SecretType) -> String { @@ -33,14 +33,21 @@ extension OpenSSHKeyWriter { return Data(bytes: &endian, count: UInt32.bitWidth/8) + data } - public func readData() {} -} - -extension OpenSSHKeyWriter { - - public enum Constants { - public static let curveIdentifier = "nistp256" - public static let curveType = "ecdsa-sha2-nistp256" + public func curveIdentifier(for algorithm: Algorithm, length: Int) -> String { + switch algorithm { + case .ellipticCurve: + return "nistp" + String(describing: length) + case .rsa: + return "ssh-rsa" + } } + public func curveType(for algorithm: Algorithm, length: Int) -> String { + switch algorithm { + case .ellipticCurve: + return "ecdsa-sha2-nistp" + String(describing: length) + case .rsa: + return "ssh-rsa" + } + } } diff --git a/SecretKit/Secret.swift b/SecretKit/Secret.swift index a4c40b5..dd65cee 100644 --- a/SecretKit/Secret.swift +++ b/SecretKit/Secret.swift @@ -1,6 +1,23 @@ public protocol Secret: Identifiable, Hashable { var name: String { get } + var algorithm: Algorithm { get } + var keySize: Int { get } var publicKey: Data { get } } + +public enum Algorithm { + case ellipticCurve, rsa + public init(secAttr: NSNumber) { + let secAttrString = secAttr.stringValue as CFString + switch secAttrString { + case kSecAttrKeyTypeEC: + self = .ellipticCurve + case kSecAttrKeyTypeRSA: + self = .rsa + default: + fatalError() + } + } +} diff --git a/SecretKit/SecureEnclave/SecureEnclaveSecret.swift b/SecretKit/SecureEnclave/SecureEnclaveSecret.swift index 3ab9f5f..cb6bcc1 100644 --- a/SecretKit/SecureEnclave/SecureEnclaveSecret.swift +++ b/SecretKit/SecureEnclave/SecureEnclaveSecret.swift @@ -7,6 +7,8 @@ extension SecureEnclave { public let id: Data public let name: String + public let algorithm = Algorithm.ellipticCurve + public let keySize = 256 public let publicKey: Data } diff --git a/SecretKit/SmartCard/SmartCardSecret.swift b/SecretKit/SmartCard/SmartCardSecret.swift index 6444470..977d4dc 100644 --- a/SecretKit/SmartCard/SmartCardSecret.swift +++ b/SecretKit/SmartCard/SmartCardSecret.swift @@ -7,6 +7,8 @@ extension SmartCard { public let id: Data public let name: String + public let algorithm: Algorithm + public let keySize: Int public let publicKey: Data } diff --git a/SecretKit/SmartCard/SmartCardStore.swift b/SecretKit/SmartCard/SmartCardStore.swift index b1ed962..a89032e 100644 --- a/SecretKit/SmartCard/SmartCardStore.swift +++ b/SecretKit/SmartCard/SmartCardStore.swift @@ -61,7 +61,18 @@ extension SmartCard { } let key = untypedSafe as! SecKey var signError: SecurityError? - guard let signature = SecKeyCreateSignature(key, .ecdsaSignatureMessageX962SHA256, data as CFData, &signError) else { + let signatureAlgorithm: SecKeyAlgorithm + switch (secret.algorithm, secret.keySize) { + case (.ellipticCurve, 256): + signatureAlgorithm = .ecdsaSignatureMessageX962SHA256 + case (.ellipticCurve, 384): + signatureAlgorithm = .ecdsaSignatureMessageX962SHA384 + case (.rsa, _): + signatureAlgorithm = .rsaSignatureRaw + default: + fatalError() + } + guard let signature = SecKeyCreateSignature(key, signatureAlgorithm, data as CFData, &signError) else { throw SigningError(error: signError) } return signature as Data @@ -90,8 +101,6 @@ extension SmartCard.Store { guard let tokenID = tokenID else { return } let attributes = [ kSecClass: kSecClassKey, - kSecAttrKeyType: kSecAttrKeyTypeEC, - kSecAttrKeySizeInBits: 256, kSecAttrTokenID: tokenID, kSecReturnRef: true, kSecMatchLimit: kSecMatchLimitAll, @@ -103,11 +112,13 @@ extension SmartCard.Store { let wrapped: [SmartCard.Secret] = typed.map { let name = $0[kSecAttrLabel] as? String ?? "Unnamed" let tokenID = $0[kSecAttrApplicationLabel] as! Data + let algorithm = Algorithm(secAttr: $0[kSecAttrKeyType] as! NSNumber) + let keySize = $0[kSecAttrKeySizeInBits] as! Int let publicKeyRef = $0[kSecValueRef] as! SecKey let publicKeySecRef = SecKeyCopyPublicKey(publicKeyRef)! let publicKeyAttributes = SecKeyCopyAttributes(publicKeySecRef) as! [CFString: Any] let publicKey = publicKeyAttributes[kSecValueData] as! Data - return SmartCard.Secret(id: tokenID, name: name, publicKey: publicKey) + return SmartCard.Secret(id: tokenID, name: name, algorithm: algorithm, keySize: keySize, publicKey: publicKey) } secrets.append(contentsOf: wrapped) } diff --git a/Secretive/Preview Content/PreviewStore.swift b/Secretive/Preview Content/PreviewStore.swift index 6567697..db9980a 100644 --- a/Secretive/Preview Content/PreviewStore.swift +++ b/Secretive/Preview Content/PreviewStore.swift @@ -9,6 +9,8 @@ extension Preview { let id = UUID().uuidString let name: String + let algorithm = Algorithm.ellipticCurve + let keySize = 256 let publicKey = UUID().uuidString.data(using: .utf8)! } From 668f46c803955d6808710b170d30be0867010f0b Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Mon, 9 Mar 2020 22:06:51 -0700 Subject: [PATCH 2/3] Restrict to EC only --- SecretAgent/Agent.swift | 4 ---- SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift | 4 ---- SecretKit/Secret.swift | 4 +--- SecretKit/SmartCard/SmartCardStore.swift | 3 +-- 4 files changed, 2 insertions(+), 13 deletions(-) diff --git a/SecretAgent/Agent.swift b/SecretAgent/Agent.swift index 617ebe8..2ee5908 100644 --- a/SecretAgent/Agent.swift +++ b/SecretAgent/Agent.swift @@ -102,10 +102,6 @@ extension Agent { rawRepresentation = try CryptoKit.P256.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation case (.ellipticCurve, 384): rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation - case (.rsa, 1024): - fatalError() - case (.rsa, 2048): - fatalError() default: fatalError() } diff --git a/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift b/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift index 9d2a6a5..b4d172a 100644 --- a/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift +++ b/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift @@ -37,8 +37,6 @@ extension OpenSSHKeyWriter { switch algorithm { case .ellipticCurve: return "nistp" + String(describing: length) - case .rsa: - return "ssh-rsa" } } @@ -46,8 +44,6 @@ extension OpenSSHKeyWriter { switch algorithm { case .ellipticCurve: return "ecdsa-sha2-nistp" + String(describing: length) - case .rsa: - return "ssh-rsa" } } } diff --git a/SecretKit/Secret.swift b/SecretKit/Secret.swift index dd65cee..7e54b4c 100644 --- a/SecretKit/Secret.swift +++ b/SecretKit/Secret.swift @@ -8,14 +8,12 @@ public protocol Secret: Identifiable, Hashable { } public enum Algorithm { - case ellipticCurve, rsa + case ellipticCurve public init(secAttr: NSNumber) { let secAttrString = secAttr.stringValue as CFString switch secAttrString { case kSecAttrKeyTypeEC: self = .ellipticCurve - case kSecAttrKeyTypeRSA: - self = .rsa default: fatalError() } diff --git a/SecretKit/SmartCard/SmartCardStore.swift b/SecretKit/SmartCard/SmartCardStore.swift index a89032e..08e10d7 100644 --- a/SecretKit/SmartCard/SmartCardStore.swift +++ b/SecretKit/SmartCard/SmartCardStore.swift @@ -67,8 +67,6 @@ extension SmartCard { signatureAlgorithm = .ecdsaSignatureMessageX962SHA256 case (.ellipticCurve, 384): signatureAlgorithm = .ecdsaSignatureMessageX962SHA384 - case (.rsa, _): - signatureAlgorithm = .rsaSignatureRaw default: fatalError() } @@ -102,6 +100,7 @@ extension SmartCard.Store { let attributes = [ kSecClass: kSecClassKey, kSecAttrTokenID: tokenID, + kSecAttrKeyType: kSecAttrKeyTypeEC, // Restrict to EC kSecReturnRef: true, kSecMatchLimit: kSecMatchLimitAll, kSecReturnAttributes: true From b4f7b820d764521f6d857158a4b94db2cc2ceb7a Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Mon, 9 Mar 2020 22:12:40 -0700 Subject: [PATCH 3/3] notes --- SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift b/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift index b4d172a..ab08f48 100644 --- a/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift +++ b/SecretKit/Common/OpenSSH/OpenSSHKeyWriter.swift @@ -1,7 +1,7 @@ import Foundation import CryptoKit -// For the moment, only supports ecdsa-sha2-nistp256 keys +// For the moment, only supports ecdsa-sha2-nistp256 and ecdsa-sha2-nistp386 keys public struct OpenSSHKeyWriter { public init() {