diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index 21697c6..ef226ce 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -9,7 +9,8 @@ public final class Agent: Sendable { private let storeList: SecretStoreList private let witness: SigningWitness? - private let writer = OpenSSHKeyWriter() + private let publicKeyWriter = OpenSSHPublicKeyWriter() + private let signatureWriter = OpenSSHSignatureWriter() private let requestTracer = SigningRequestTracer() private let certificateHandler = OpenSSHCertificateHandler() private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "Agent") @@ -43,7 +44,7 @@ extension Agent { guard data.count > 4 else { return false} let requestTypeInt = data[4] guard let requestType = SSHAgent.RequestType(rawValue: requestTypeInt) else { - writer.write(OpenSSHKeyWriter().lengthAndData(of: SSHAgent.ResponseType.agentFailure.data)) + writer.write(SSHAgent.ResponseType.agentFailure.data.lengthAndData) logger.debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription)") return true } @@ -75,8 +76,7 @@ extension Agent { response.append(SSHAgent.ResponseType.agentFailure.data) logger.debug("Agent returned \(SSHAgent.ResponseType.agentFailure.debugDescription)") } - let full = OpenSSHKeyWriter().lengthAndData(of: response) - return full + return response.lengthAndData } } @@ -92,14 +92,14 @@ extension Agent { var keyData = Data() for secret in secrets { - let keyBlob = writer.data(secret: secret) - let curveData = Data(writer.curveType(for: secret.keyType).utf8) - keyData.append(writer.lengthAndData(of: keyBlob)) - keyData.append(writer.lengthAndData(of: curveData)) - + let keyBlob = publicKeyWriter.data(secret: secret) + let curveData = publicKeyWriter.openSSHIdentifier(for: secret.keyType) + keyData.append(keyBlob.lengthAndData) + keyData.append(curveData.lengthAndData) + if let (certificateData, name) = try? await certificateHandler.keyBlobAndName(for: secret) { - keyData.append(writer.lengthAndData(of: certificateData)) - keyData.append(writer.lengthAndData(of: name)) + keyData.append(certificateData.lengthAndData) + keyData.append(name.lengthAndData) count += 1 } } @@ -137,7 +137,7 @@ extension Agent { let dataToSign = reader.readNextChunk() let rawRepresentation = try await store.sign(data: dataToSign, with: secret, for: provenance) - let curveData = Data(writer.curveType(for: secret.keyType).utf8) + let curveData = publicKeyWriter.openSSHIdentifier(for: secret.keyType) let signedData: Data if secret.keyType.algorithm == .ecdsa { @@ -155,20 +155,20 @@ extension Agent { } var signatureChunk = Data() - signatureChunk.append(writer.lengthAndData(of: r)) - signatureChunk.append(writer.lengthAndData(of: s)) + signatureChunk.append(r.lengthAndData) + signatureChunk.append(s.lengthAndData) var mutSignedData = Data() var sub = Data() - sub.append(writer.lengthAndData(of: curveData)) - sub.append(writer.lengthAndData(of: signatureChunk)) - mutSignedData.append(writer.lengthAndData(of: sub)) + sub.append(curveData.lengthAndData) + sub.append(signatureChunk.lengthAndData) + mutSignedData.append(sub.lengthAndData) signedData = mutSignedData } else { var mutSignedData = Data() var sub = Data() - sub.append(writer.lengthAndData(of: Data("rsa-sha2-512".utf8))) - sub.append(writer.lengthAndData(of: rawRepresentation)) - mutSignedData.append(writer.lengthAndData(of: sub)) + sub.append("rsa-sha2-512".lengthAndData) + sub.append(rawRepresentation.lengthAndData) + mutSignedData.append(sub.lengthAndData) signedData = mutSignedData } @@ -203,7 +203,7 @@ extension Agent { func secret(matching hash: Data) async -> (AnySecretStore, AnySecret)? { for store in await storeList.stores { let allMatching = await store.secrets.filter { secret in - hash == writer.data(secret: secret) + hash == publicKeyWriter.data(secret: secret) } if let matching = allMatching.first { return (store, matching) diff --git a/Sources/Packages/Sources/SecretKit/Documentation.docc/Documentation.md b/Sources/Packages/Sources/SecretKit/Documentation.docc/Documentation.md index a7fed06..8798ca6 100644 --- a/Sources/Packages/Sources/SecretKit/Documentation.docc/Documentation.md +++ b/Sources/Packages/Sources/SecretKit/Documentation.docc/Documentation.md @@ -22,7 +22,7 @@ SecretKit is a collection of protocols describing secrets and stores. ### OpenSSH -- ``OpenSSHKeyWriter`` +- ``OpenSSHPublicKeyWriter`` - ``OpenSSHReader`` ### Signing Process diff --git a/Sources/Packages/Sources/SecretKit/KeychainTypes.swift b/Sources/Packages/Sources/SecretKit/KeychainTypes.swift index 75df0c3..debb2e1 100644 --- a/Sources/Packages/Sources/SecretKit/KeychainTypes.swift +++ b/Sources/Packages/Sources/SecretKit/KeychainTypes.swift @@ -52,16 +52,16 @@ public extension SecretStore { /// - Parameters: /// - secret: The secret which will be used for signing. /// - Returns: The appropriate algorithm. - func signatureAlgorithm(for secret: SecretType) -> SecKeyAlgorithm { + func signatureAlgorithm(for secret: SecretType) -> SecKeyAlgorithm? { switch (secret.keyType.algorithm, secret.keyType.size) { case (.ecdsa, 256): - return .ecdsaSignatureMessageX962SHA256 + .ecdsaSignatureMessageX962SHA256 case (.ecdsa, 384): - return .ecdsaSignatureMessageX962SHA384 + .ecdsaSignatureMessageX962SHA384 case (.rsa, 2048): - return .rsaSignatureMessagePKCS1v15SHA512 + .rsaSignatureMessagePKCS1v15SHA512 default: - fatalError() + nil } } diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/LengthAndData.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/LengthAndData.swift new file mode 100644 index 0000000..33acc06 --- /dev/null +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/LengthAndData.swift @@ -0,0 +1,23 @@ +import Foundation + +extension Data { + + /// Creates an OpenSSH protocol style data object, which has a length header, followed by the data payload. + /// - Returns: OpenSSH data. + package var lengthAndData: Data { + let rawLength = UInt32(count) + var endian = rawLength.bigEndian + return Data(bytes: &endian, count: UInt32.bitWidth/8) + self + } + +} + +extension String { + + /// Creates an OpenSSH protocol style data object, which has a length header, followed by the data payload. + /// - Returns: OpenSSH data. + package var lengthAndData: Data { + Data(utf8).lengthAndData + } + +} diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift index ed9d293..8d955ba 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift @@ -6,7 +6,7 @@ public actor OpenSSHCertificateHandler: Sendable { private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: NSHomeDirectory()) private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "OpenSSHCertificateHandler") - private let writer = OpenSSHKeyWriter() + private let writer = OpenSSHPublicKeyWriter() private var keyBlobsAndNames: [AnySecret: (Data, Data)] = [:] /// Initializes an OpenSSHCertificateHandler. @@ -40,10 +40,10 @@ public actor OpenSSHCertificateHandler: Sendable { let curveIdentifier = reader.readNextChunk() let publicKey = reader.readNextChunk() - let curveType = Data(certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "").utf8) - return writer.lengthAndData(of: curveType) + - writer.lengthAndData(of: curveIdentifier) + - writer.lengthAndData(of: publicKey) + let openSSHIdentifier = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "") + return openSSHIdentifier.lengthAndData + + curveIdentifier.lengthAndData + + publicKey.lengthAndData default: return nil } diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift index f07b269..0a9465c 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHKeyWriter.swift @@ -1,8 +1,8 @@ import Foundation import CryptoKit -/// Generates OpenSSH representations of Secrets. -public struct OpenSSHKeyWriter: Sendable { +/// Generates OpenSSH representations of the public key sof secrets. +public struct OpenSSHPublicKeyWriter: Sendable { /// Initializes the writer. public init() { @@ -13,15 +13,18 @@ public struct OpenSSHKeyWriter: Sendable { public func data(secret: SecretType) -> Data { switch secret.keyType.algorithm { case .ecdsa: - lengthAndData(of: Data(curveType(for: secret.keyType).utf8)) + - lengthAndData(of: Data(curveIdentifier(for: secret.keyType).utf8)) + - lengthAndData(of: secret.publicKey) + // https://datatracker.ietf.org/doc/html/rfc5656#section-3.1 + openSSHIdentifier(for: secret.keyType).lengthAndData + + ("nistp" + String(describing: secret.keyType.size)).lengthAndData + + secret.publicKey.lengthAndData case .mldsa: - lengthAndData(of: Data(curveType(for: secret.keyType).utf8)) + - lengthAndData(of: secret.publicKey) + // https://www.ietf.org/archive/id/draft-sfluhrer-ssh-mldsa-04.txt + openSSHIdentifier(for: secret.keyType).lengthAndData + + secret.publicKey.lengthAndData case .rsa: - lengthAndData(of: Data(curveType(for: secret.keyType).utf8)) + - rsa(secret: secret) + // https://datatracker.ietf.org/doc/html/rfc4253#section-6.6 + openSSHIdentifier(for: secret.keyType).lengthAndData + + rsaPublicKeyBlob(secret: secret) } } @@ -39,7 +42,7 @@ public struct OpenSSHKeyWriter: Sendable { .replacingOccurrences(of: " ", with: "-") resolvedComment = "\(dashedKeyName)@\(dashedHostName)" } - return [curveType(for: secret.keyType), data(secret: secret).base64EncodedString(), resolvedComment] + return [openSSHIdentifier(for: secret.keyType), data(secret: secret).base64EncodedString(), resolvedComment] .compactMap { $0 } .joined(separator: " ") } @@ -64,63 +67,43 @@ public struct OpenSSHKeyWriter: Sendable { } -extension OpenSSHKeyWriter { - - /// Creates an OpenSSH protocol style data object, which has a length header, followed by the data payload. - /// - Parameter data: The data payload. - /// - Returns: OpenSSH data. - public func lengthAndData(of data: Data) -> Data { - let rawLength = UInt32(data.count) - var endian = rawLength.bigEndian - return Data(bytes: &endian, count: UInt32.bitWidth/8) + data - } +extension OpenSSHPublicKeyWriter { /// The fully qualified OpenSSH identifier for the algorithm. /// - Parameters: /// - algorithm: The algorithm to identify. /// - length: The key length of the algorithm. /// - Returns: The OpenSSH identifier for the algorithm. - public func curveType(for keyType: KeyType) -> String { + public func openSSHIdentifier(for keyType: KeyType) -> String { switch (keyType.algorithm, keyType.size) { case (.ecdsa, 256), (.ecdsa, 384): "ecdsa-sha2-nistp" + String(describing: keyType.size) case (.mldsa, 65), (.mldsa, 87): - "ssh-mldsa" + String(describing: keyType.size) + "ssh-mldsa-" + String(describing: keyType.size) case (.rsa, _): - "ssh-rsa" + "ssh-rsa" default: "unknown" } } - /// The OpenSSH identifier for an algorithm. - /// - Parameters: - /// - algorithm: The algorithm to identify. - /// - length: The key length of the algorithm. - /// - Returns: The OpenSSH identifier for the algorithm. - private func curveIdentifier(for keyType: KeyType) -> String { - switch keyType.algorithm { - case .ecdsa: - "nistp" + String(describing: keyType.size) - case .mldsa: - "mldsa" + String(describing: keyType.size) - default: - fatalError() - } - } +} - public func rsa(secret: SecretType) -> Data { +extension OpenSSHPublicKeyWriter { + + public func rsaPublicKeyBlob(secret: SecretType) -> Data { // Cheap way to pull out e and n as defined in https://datatracker.ietf.org/doc/html/rfc4253 // Keychain stores it as a thin ASN.1 wrapper with this format: // [4 byte prefix][2 byte prefix][n][2 byte prefix][e] - // Rather than parse out the whole ASN.1 blob, we know how this should be formatted, so pull values directly. + // Rather than parse out the whole ASN.1 blob, we'll cheat and pull values directly since + // we only support one key type, and the keychain always gives it in a specific format. let keySize = secret.keyType.size guard secret.keyType.algorithm == .rsa && keySize == 2048 else { fatalError() } let length = secret.keyType.size/8 let data = secret.publicKey let n = Data(data[8..<(9+length)]) let e = Data(data[(2+9+length)...]) - return lengthAndData(of: e) + lengthAndData(of: n) + return e.lengthAndData + n.lengthAndData } } diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift new file mode 100644 index 0000000..8ac059c --- /dev/null +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift @@ -0,0 +1,69 @@ +import Foundation +import CryptoKit + +/// Generates OpenSSH representations of Secrets. +public struct OpenSSHSignatureWriter: Sendable { + + /// Initializes the writer. + public init() { + } + + /// Generates an OpenSSH data payload identifying the secret. + /// - Returns: OpenSSH data payload identifying the secret. + public func data(secret: SecretType, signature: Data) -> Data { + switch secret.keyType.algorithm { + case .ecdsa: + // https://datatracker.ietf.org/doc/html/rfc5656#section-3.1 + fatalError() + case .mldsa: + // https://www.ietf.org/archive/id/draft-sfluhrer-ssh-mldsa-04.txt + fatalError() + case .rsa: + // https://datatracker.ietf.org/doc/html/rfc4253#section-6.6 + fatalError() + } + } + +} + +extension OpenSSHSignatureWriter { + + + /// The fully qualified OpenSSH identifier for the algorithm. + /// - Parameters: + /// - algorithm: The algorithm to identify. + /// - length: The key length of the algorithm. + /// - Returns: The OpenSSH identifier for the algorithm. + public func openSSHIdentifier(for keyType: KeyType) -> String { + switch (keyType.algorithm, keyType.size) { + case (.ecdsa, 256), (.ecdsa, 384): + "ecdsa-sha2-nistp" + String(describing: keyType.size) + case (.mldsa, 65), (.mldsa, 87): + "ssh-mldsa-" + String(describing: keyType.size) + case (.rsa, _): + "ssh-rsa" + default: + "unknown" + } + } + +} + +extension OpenSSHSignatureWriter { + + public func rsaPublicKeyBlob(secret: SecretType) -> Data { + // Cheap way to pull out e and n as defined in https://datatracker.ietf.org/doc/html/rfc4253 + // Keychain stores it as a thin ASN.1 wrapper with this format: + // [4 byte prefix][2 byte prefix][n][2 byte prefix][e] + // Rather than parse out the whole ASN.1 blob, we'll cheat and pull values directly since + // we only support one key type, and the keychain always gives it in a specific format. + let keySize = secret.keyType.size + guard secret.keyType.algorithm == .rsa && keySize == 2048 else { fatalError() } + let length = secret.keyType.size/8 + let data = secret.publicKey + let n = Data(data[8..<(9+length)]) + let e = Data(data[(2+9+length)...]) + return e.lengthAndData + n.lengthAndData + } + +} diff --git a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift index ce3dcbe..ada02d7 100644 --- a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift +++ b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift @@ -6,7 +6,7 @@ public final class PublicKeyFileStoreController: Sendable { private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "PublicKeyFileStoreController") private let directory: String - private let keyWriter = OpenSSHKeyWriter() + private let keyWriter = OpenSSHPublicKeyWriter() /// Initializes a PublicKeyFileStoreController. public init(homeDirectory: String) { diff --git a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift index 379e3d0..3cf29b7 100644 --- a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift +++ b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift @@ -79,7 +79,8 @@ extension SmartCard { } let key = untypedSafe as! SecKey var signError: SecurityError? - guard let signature = SecKeyCreateSignature(key, signatureAlgorithm(for: secret), data as CFData, &signError) else { + guard let algorithm = signatureAlgorithm(for: secret) else { throw UnsupportKeyType() } + guard let signature = SecKeyCreateSignature(key, algorithm, data as CFData, &signError) else { throw SigningError(error: signError) } return signature as Data @@ -153,7 +154,7 @@ extension SmartCard.Store { var untyped: CFTypeRef? SecItemCopyMatching(attributes, &untyped) guard let typed = untyped as? [[CFString: Any]] else { return } - let wrapped = typed.map { + let wrapped: [SecretType] = typed.compactMap { let name = $0[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret) let tokenID = $0[kSecAttrApplicationLabel] as! Data let algorithmSecAttr = $0[kSecAttrKeyType] as! NSNumber @@ -163,7 +164,9 @@ extension SmartCard.Store { let publicKeyAttributes = SecKeyCopyAttributes(publicKeySecRef) as! [CFString: Any] let publicKey = publicKeyAttributes[kSecValueData] as! Data let attributes = Attributes(keyType: KeyType(secAttr: algorithmSecAttr, size: keySize)!, authentication: .unknown) - return SmartCard.Secret(id: tokenID, name: name, publicKey: publicKey, attributes: attributes) + let secret = SmartCard.Secret(id: tokenID, name: name, publicKey: publicKey, attributes: attributes) + guard signatureAlgorithm(for: secret) != nil else { return nil } + return secret } state.secrets.append(contentsOf: wrapped) } @@ -178,3 +181,9 @@ extension TKTokenWatcher { } } + +extension SmartCard { + + public struct UnsupportKeyType: Error {} + +} diff --git a/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift b/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift index c649daa..b78cda9 100644 --- a/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift +++ b/Sources/Packages/Tests/SecretAgentKitTests/StubStore.swift @@ -45,7 +45,7 @@ extension Stub { let privateData = (privateAttributes[kSecValueData] as! Data) let secret = Secret(keySize: size, publicKey: publicData, privateKey: privateData) print(secret) - print("Public Key OpenSSH: \(OpenSSHKeyWriter().openSSHString(secret: secret))") + print("Public Key OpenSSH: \(OpenSSHPublicKeyWriter().openSSHString(secret: secret))") } public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data { diff --git a/Sources/Packages/Tests/SecretKitTests/AnySecretTests.swift b/Sources/Packages/Tests/SecretKitTests/AnySecretTests.swift index 3675270..b8e4b2b 100644 --- a/Sources/Packages/Tests/SecretKitTests/AnySecretTests.swift +++ b/Sources/Packages/Tests/SecretKitTests/AnySecretTests.swift @@ -4,11 +4,12 @@ import Testing @testable import SecureEnclaveSecretKit @testable import SmartCardSecretKit + @Suite struct AnySecretTests { @Test func eraser() { let data = Data(UUID().uuidString.utf8) - let secret = SmartCard.Secret(id: data, name: "Name", publicKey: data, attributes: Attributes(keyType: KeyType(algorithm: .ecdsa, size: 256))) + let secret = SmartCard.Secret(id: data, name: "Name", publicKey: data, attributes: Attributes(keyType: KeyType(algorithm: .ecdsa, size: 256), authentication: .notRequired)) let erased = AnySecret(secret) #expect(erased.id == secret.id as AnyHashable) #expect(erased.name == secret.name) diff --git a/Sources/Packages/Tests/SecretKitTests/OpenSSHWriterTests.swift b/Sources/Packages/Tests/SecretKitTests/OpenSSHPublicKeyWriterTests.swift similarity index 89% rename from Sources/Packages/Tests/SecretKitTests/OpenSSHWriterTests.swift rename to Sources/Packages/Tests/SecretKitTests/OpenSSHPublicKeyWriterTests.swift index 1cb5ec7..92c3132 100644 --- a/Sources/Packages/Tests/SecretKitTests/OpenSSHWriterTests.swift +++ b/Sources/Packages/Tests/SecretKitTests/OpenSSHPublicKeyWriterTests.swift @@ -4,9 +4,9 @@ import Testing @testable import SecureEnclaveSecretKit @testable import SmartCardSecretKit -@Suite struct OpenSSHWriterTests { +@Suite struct OpenSSHPublicKeyWriterTests { - let writer = OpenSSHKeyWriter() + let writer = OpenSSHPublicKeyWriter() @Test func ecdsa256MD5Fingerprint() { #expect(writer.openSSHMD5Fingerprint(secret: Constants.ecdsa256Secret) == "dc:60:4d:ff:c2:d9:18:8b:2f:24:40:b5:7f:43:47:e5") @@ -44,11 +44,11 @@ import Testing } -extension OpenSSHWriterTests { +extension OpenSSHPublicKeyWriterTests { enum Constants { - static let ecdsa256Secret = SmartCard.Secret(id: Data(), name: "Test Key (ECDSA 256)", publicKey: Data(base64Encoded: "BOVEjgAA5PHqRgwykjN5qM21uWCHFSY/Sqo5gkHAkn+e1MMQKHOLga7ucB9b3mif33MBid59GRK9GEPVlMiSQwo=")!, attributes: Attributes(keyType: KeyType(algorithm: .ecdsa, size: 256), publicKeyAttribution: "test@example.com")) - static let ecdsa384Secret = SmartCard.Secret(id: Data(), name: "Test Key (ECDSA 384)", publicKey: Data(base64Encoded: "BG2MNc/C5OTHFE2tBvbZCVcpOGa8vBMquiTLkH4lwkeqOPxhi+PyYUfQZMTRJNPiTyWPoMBqNiCIFRVv60yPN/AHufHaOgbdTP42EgMlMMImkAjYUEv9DESHTVIs2PW1yQ==")!, attributes: Attributes(keyType: KeyType(algorithm: .ecdsa, size: 384), publicKeyAttribution: "test@example.com")) + static let ecdsa256Secret = SmartCard.Secret(id: Data(), name: "Test Key (ECDSA 256)", publicKey: Data(base64Encoded: "BOVEjgAA5PHqRgwykjN5qM21uWCHFSY/Sqo5gkHAkn+e1MMQKHOLga7ucB9b3mif33MBid59GRK9GEPVlMiSQwo=")!, attributes: Attributes(keyType: KeyType(algorithm: .ecdsa, size: 256), authentication: .notRequired, publicKeyAttribution: "test@example.com")) + static let ecdsa384Secret = SmartCard.Secret(id: Data(), name: "Test Key (ECDSA 384)", publicKey: Data(base64Encoded: "BG2MNc/C5OTHFE2tBvbZCVcpOGa8vBMquiTLkH4lwkeqOPxhi+PyYUfQZMTRJNPiTyWPoMBqNiCIFRVv60yPN/AHufHaOgbdTP42EgMlMMImkAjYUEv9DESHTVIs2PW1yQ==")!, attributes: Attributes(keyType: KeyType(algorithm: .ecdsa, size: 384), authentication: .notRequired, publicKeyAttribution: "test@example.com")) } diff --git a/Sources/Secretive/Views/SecretDetailView.swift b/Sources/Secretive/Views/SecretDetailView.swift index 3979371..68a1e05 100644 --- a/Sources/Secretive/Views/SecretDetailView.swift +++ b/Sources/Secretive/Views/SecretDetailView.swift @@ -5,7 +5,7 @@ struct SecretDetailView: View { let secret: SecretType - private let keyWriter = OpenSSHKeyWriter() + private let keyWriter = OpenSSHPublicKeyWriter() private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: NSHomeDirectory().replacingOccurrences(of: Bundle.main.hostBundleID, with: Bundle.main.agentBundleID)) var body: some View {