mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-08-30 17:10:56 +00:00
Cleanup
This commit is contained in:
parent
7d6223a327
commit
698b7571c8
@ -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)
|
||||
|
@ -22,7 +22,7 @@ SecretKit is a collection of protocols describing secrets and stores.
|
||||
|
||||
### OpenSSH
|
||||
|
||||
- ``OpenSSHKeyWriter``
|
||||
- ``OpenSSHPublicKeyWriter``
|
||||
- ``OpenSSHReader``
|
||||
|
||||
### Signing Process
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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<SecretType: Secret>(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<SecretType: Secret>(secret: SecretType) -> Data {
|
||||
extension OpenSSHPublicKeyWriter {
|
||||
|
||||
public func rsaPublicKeyBlob<SecretType: Secret>(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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<SecretType: Secret>(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<SecretType: Secret>(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
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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 {}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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"))
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ struct SecretDetailView<SecretType: Secret>: 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 {
|
||||
|
Loading…
Reference in New Issue
Block a user