From 13c2ecc14a9971077eb5137ed663b51992b1ff9a Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 24 Aug 2025 19:56:47 -0700 Subject: [PATCH] MLDSA working. --- .../SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift | 12 ++++++++---- .../SecretKit/OpenSSH/OpenSSHSignatureWriter.swift | 13 +++++++++++-- .../SecureEnclaveSecretKit/SecureEnclaveStore.swift | 9 +++++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift index 0a9465c..d809755 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift @@ -76,10 +76,14 @@ extension OpenSSHPublicKeyWriter { /// - 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 (.ecdsa, 256): + "ecdsa-sha2-nistp256" + case (.ecdsa, 384): + "ecdsa-sha2-nistp384" + case (.mldsa, 65): + "ssh-mldsa-65" + case (.mldsa, 87): + "ssh-mldsa-87" case (.rsa, _): "ssh-rsa" default: diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift index e17bf91..b713d53 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHSignatureWriter.swift @@ -16,8 +16,8 @@ public struct OpenSSHSignatureWriter: Sendable { // https://datatracker.ietf.org/doc/html/rfc5656#section-3.1 ecdsaSignature(signature, keyType: secret.keyType) case .mldsa: - // https://www.ietf.org/archive/id/draft-sfluhrer-ssh-mldsa-04.txt - fatalError() + // https://datatracker.ietf.org/doc/html/draft-sfluhrer-ssh-mldsa-00#name-public-key-algorithms + mldsaSignature(signature, keyType: secret.keyType) case .rsa: // https://datatracker.ietf.org/doc/html/rfc4253#section-6.6 rsaSignature(signature) @@ -54,6 +54,15 @@ extension OpenSSHSignatureWriter { return mutSignedData } + func mldsaSignature(_ rawRepresentation: Data, keyType: KeyType) -> Data { + var mutSignedData = Data() + var sub = Data() + sub.append(OpenSSHPublicKeyWriter().openSSHIdentifier(for: keyType).lengthAndData) + sub.append(rawRepresentation.lengthAndData) + mutSignedData.append(sub.lengthAndData) + return mutSignedData + } + func rsaSignature(_ rawRepresentation: Data) -> Data { var mutSignedData = Data() var sub = Data() diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index cad333d..a001c4f 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -39,10 +39,10 @@ extension SecureEnclave { context = existing.context } else { let newContext = LAContext() - newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button") + newContext.localizedReason = String(localized: .authContextRequestSignatureDescription(appName: provenance.origin.displayName, secretName: secret.name)) + newContext.localizedCancelTitle = String(localized: .authContextRequestDenyButton) context = newContext } - context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)") let queryAttributes = KeychainDictionary([ kSecClass: Constants.keyClass, @@ -68,7 +68,7 @@ extension SecureEnclave { switch (attributes.keyType.algorithm, attributes.keyType.size) { case (.ecdsa, 256): - let key = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: keyData) + let key = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: keyData, authenticationContext: context) return try key.signature(for: data).rawRepresentation case (.mldsa, 65): guard #available(macOS 26.0, *) else { throw UnsupportedAlgorithmError() } @@ -143,7 +143,8 @@ extension SecureEnclave { kSecClass: Constants.keyClass, kSecAttrService: Constants.keyTag, kSecUseDataProtectionKeychain: true, - kSecAttrAccount: String(decoding: secret.id, as: UTF8.self) + kSecAttrAccount: String(decoding: secret.id, as: UTF8.self), + kSecAttrCanSign: true, ]) let status = SecItemDelete(deleteAttributes) if status != errSecSuccess {