This commit is contained in:
Max Goedjen 2025-09-06 14:19:40 -07:00
parent a94c9fd1b5
commit 2994861f45
No known key found for this signature in database
4 changed files with 29 additions and 39 deletions

View File

@ -92,16 +92,8 @@ extension Agent {
/// - provenance: A ``SecretKit.SigningRequestProvenance`` object describing the origin of the request.
/// - Returns: An OpenSSH formatted Data payload containing the signed data response.
func sign(data: Data, keyBlob: Data, provenance: SigningRequestProvenance) async throws -> Data {
// Check if hash is actually an openssh certificate and reconstruct the public key if it is
let resolvedBlob: Data
if let certificatePublicKey = await certificateHandler.publicKeyHash(from: keyBlob) {
resolvedBlob = certificatePublicKey
} else {
resolvedBlob = keyBlob
}
guard let (secret, store) = await secret(matching: resolvedBlob) else {
logger.debug("Agent did not have a key matching \(resolvedBlob as NSData)")
guard let (secret, store) = await secret(matching: keyBlob) else {
logger.debug("Agent did not have a key matching \(keyBlob as NSData)")
throw NoMatchingKeyError()
}

View File

@ -1,5 +1,6 @@
import Foundation
import OSLog
import SecretKit
/// Manages storage and lookup for OpenSSH certificates.
public actor OpenSSHCertificateHandler: Sendable {
@ -25,33 +26,6 @@ public actor OpenSSHCertificateHandler: Sendable {
}
}
/// Reconstructs a public key from a ``Data``, if that ``Data`` contains an OpenSSH certificate hash. Currently only ecdsa certificates are supported
/// - Parameter certBlock: The openssh certificate to extract the public key from
/// - Returns: A ``Data`` object containing the public key in OpenSSH wire format if the ``Data`` is an OpenSSH certificate hash, otherwise nil.
public func publicKeyHash(from hash: Data) -> Data? {
let reader = OpenSSHReader(data: hash)
do {
let certType = String(decoding: try reader.readNextChunk(), as: UTF8.self)
switch certType {
case "ecdsa-sha2-nistp256-cert-v01@openssh.com",
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
"ecdsa-sha2-nistp521-cert-v01@openssh.com":
_ = try reader.readNextChunk() // nonce
let curveIdentifier = try reader.readNextChunk()
let publicKey = try reader.readNextChunk()
let openSSHIdentifier = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "")
return openSSHIdentifier.lengthAndData +
curveIdentifier.lengthAndData +
publicKey.lengthAndData
default:
return nil
}
} catch {
return nil
}
}
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
/// - Parameter secret: The secret to search for a certificate with
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.

View File

@ -1,7 +1,7 @@
import Foundation
/// Reads OpenSSH protocol data.
public final class OpenSSHReader {
final class OpenSSHReader {
var remaining: Data

View File

@ -59,11 +59,35 @@ extension SSHAgentInputParser {
func signatureRequestContext(from data: Data) throws -> SSHAgent.Request.SignatureRequestContext {
let reader = OpenSSHReader(data: data)
let keyBlob = try reader.readNextChunk()
let rawKeyBlob = try reader.readNextChunk()
let keyBlob = certificatePublicKeyBlob(from: rawKeyBlob) ?? rawKeyBlob
let dataToSign = try reader.readNextChunk()
return SSHAgent.Request.SignatureRequestContext(keyBlob: keyBlob, dataToSign: dataToSign)
}
func certificatePublicKeyBlob(from hash: Data) -> Data? {
let reader = OpenSSHReader(data: hash)
do {
let certType = String(decoding: try reader.readNextChunk(), as: UTF8.self)
switch certType {
case "ecdsa-sha2-nistp256-cert-v01@openssh.com",
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
"ecdsa-sha2-nistp521-cert-v01@openssh.com":
_ = try reader.readNextChunk() // nonce
let curveIdentifier = try reader.readNextChunk()
let publicKey = try reader.readNextChunk()
let openSSHIdentifier = certType.replacingOccurrences(of: "-cert-v01@openssh.com", with: "")
return openSSHIdentifier.lengthAndData +
curveIdentifier.lengthAndData +
publicKey.lengthAndData
default:
return nil
}
} catch {
return nil
}
}
}