MLDSA working.

This commit is contained in:
Max Goedjen 2025-08-24 19:56:47 -07:00
parent 005010c918
commit 13c2ecc14a
No known key found for this signature in database
3 changed files with 24 additions and 10 deletions

View File

@ -76,10 +76,14 @@ extension OpenSSHPublicKeyWriter {
/// - Returns: The OpenSSH identifier for the algorithm. /// - Returns: The OpenSSH identifier for the algorithm.
public func openSSHIdentifier(for keyType: KeyType) -> String { public func openSSHIdentifier(for keyType: KeyType) -> String {
switch (keyType.algorithm, keyType.size) { switch (keyType.algorithm, keyType.size) {
case (.ecdsa, 256), (.ecdsa, 384): case (.ecdsa, 256):
"ecdsa-sha2-nistp" + String(describing: keyType.size) "ecdsa-sha2-nistp256"
case (.mldsa, 65), (.mldsa, 87): case (.ecdsa, 384):
"ssh-mldsa-" + String(describing: keyType.size) "ecdsa-sha2-nistp384"
case (.mldsa, 65):
"ssh-mldsa-65"
case (.mldsa, 87):
"ssh-mldsa-87"
case (.rsa, _): case (.rsa, _):
"ssh-rsa" "ssh-rsa"
default: default:

View File

@ -16,8 +16,8 @@ public struct OpenSSHSignatureWriter: Sendable {
// https://datatracker.ietf.org/doc/html/rfc5656#section-3.1 // https://datatracker.ietf.org/doc/html/rfc5656#section-3.1
ecdsaSignature(signature, keyType: secret.keyType) ecdsaSignature(signature, keyType: secret.keyType)
case .mldsa: case .mldsa:
// https://www.ietf.org/archive/id/draft-sfluhrer-ssh-mldsa-04.txt // https://datatracker.ietf.org/doc/html/draft-sfluhrer-ssh-mldsa-00#name-public-key-algorithms
fatalError() mldsaSignature(signature, keyType: secret.keyType)
case .rsa: case .rsa:
// https://datatracker.ietf.org/doc/html/rfc4253#section-6.6 // https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
rsaSignature(signature) rsaSignature(signature)
@ -54,6 +54,15 @@ extension OpenSSHSignatureWriter {
return mutSignedData 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 { func rsaSignature(_ rawRepresentation: Data) -> Data {
var mutSignedData = Data() var mutSignedData = Data()
var sub = Data() var sub = Data()

View File

@ -39,10 +39,10 @@ extension SecureEnclave {
context = existing.context context = existing.context
} else { } else {
let newContext = LAContext() 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 = newContext
} }
context.localizedReason = String(localized: "auth_context_request_signature_description_\(provenance.origin.displayName)_\(secret.name)")
let queryAttributes = KeychainDictionary([ let queryAttributes = KeychainDictionary([
kSecClass: Constants.keyClass, kSecClass: Constants.keyClass,
@ -68,7 +68,7 @@ extension SecureEnclave {
switch (attributes.keyType.algorithm, attributes.keyType.size) { switch (attributes.keyType.algorithm, attributes.keyType.size) {
case (.ecdsa, 256): 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 return try key.signature(for: data).rawRepresentation
case (.mldsa, 65): case (.mldsa, 65):
guard #available(macOS 26.0, *) else { throw UnsupportedAlgorithmError() } guard #available(macOS 26.0, *) else { throw UnsupportedAlgorithmError() }
@ -143,7 +143,8 @@ extension SecureEnclave {
kSecClass: Constants.keyClass, kSecClass: Constants.keyClass,
kSecAttrService: Constants.keyTag, kSecAttrService: Constants.keyTag,
kSecUseDataProtectionKeychain: true, kSecUseDataProtectionKeychain: true,
kSecAttrAccount: String(decoding: secret.id, as: UTF8.self) kSecAttrAccount: String(decoding: secret.id, as: UTF8.self),
kSecAttrCanSign: true,
]) ])
let status = SecItemDelete(deleteAttributes) let status = SecItemDelete(deleteAttributes)
if status != errSecSuccess { if status != errSecSuccess {