Supporting different EC sizes, RSA not working yet
This commit is contained in:
parent
603d021939
commit
945907cfd4
|
@ -65,7 +65,7 @@ extension Agent {
|
|||
for secret in secrets {
|
||||
let keyBlob = writer.data(secret: secret)
|
||||
keyData.append(writer.lengthAndData(of: keyBlob))
|
||||
let curveData = OpenSSHKeyWriter.Constants.curveType.data(using: .utf8)!
|
||||
let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!
|
||||
keyData.append(writer.lengthAndData(of: curveData))
|
||||
}
|
||||
os_log(.debug, "Agent enumerated %@ identities", secrets.count as NSNumber)
|
||||
|
@ -92,13 +92,28 @@ extension Agent {
|
|||
let derSignature = try store.sign(data: dataToSign, with: secret)
|
||||
// TODO: Move this
|
||||
notifier.notify(accessTo: secret)
|
||||
let curveData = OpenSSHKeyWriter.Constants.curveType.data(using: .utf8)!
|
||||
let curveData = writer.curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!
|
||||
|
||||
// Convert from DER formatted rep to raw (r||s)
|
||||
let signature = try CryptoKit.P256.Signing.ECDSASignature(derRepresentation: derSignature)
|
||||
let rawLength = signature.rawRepresentation.count/2
|
||||
let r = signature.rawRepresentation[0..<rawLength]
|
||||
let s = signature.rawRepresentation[rawLength...]
|
||||
|
||||
let rawRepresentation: Data
|
||||
switch (secret.algorithm, secret.keySize) {
|
||||
case (.ellipticCurve, 256):
|
||||
rawRepresentation = try CryptoKit.P256.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation
|
||||
case (.ellipticCurve, 384):
|
||||
rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation
|
||||
case (.rsa, 1024):
|
||||
fatalError()
|
||||
case (.rsa, 2048):
|
||||
fatalError()
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
|
||||
|
||||
let rawLength = rawRepresentation.count/2
|
||||
let r = rawRepresentation[0..<rawLength]
|
||||
let s = rawRepresentation[rawLength...]
|
||||
|
||||
var signatureChunk = Data()
|
||||
signatureChunk.append(writer.lengthAndData(of: r))
|
||||
|
|
|
@ -6,6 +6,8 @@ public struct AnySecret: Secret {
|
|||
fileprivate let hashable: AnyHashable
|
||||
fileprivate let _id: () -> AnyHashable
|
||||
fileprivate let _name: () -> String
|
||||
fileprivate let _algorithm: () -> Algorithm
|
||||
fileprivate let _keySize: () -> Int
|
||||
fileprivate let _publicKey: () -> Data
|
||||
|
||||
public init<T>(_ secret: T) where T: Secret {
|
||||
|
@ -14,26 +16,38 @@ public struct AnySecret: Secret {
|
|||
hashable = secret.hashable
|
||||
_id = secret._id
|
||||
_name = secret._name
|
||||
_algorithm = secret._algorithm
|
||||
_keySize = secret._keySize
|
||||
_publicKey = secret._publicKey
|
||||
} else {
|
||||
base = secret as Any
|
||||
self.hashable = secret
|
||||
_id = { secret.id as AnyHashable }
|
||||
_name = { secret.name }
|
||||
_algorithm = { secret.algorithm }
|
||||
_keySize = { secret.keySize }
|
||||
_publicKey = { secret.publicKey }
|
||||
}
|
||||
}
|
||||
|
||||
public var id: AnyHashable {
|
||||
return _id()
|
||||
_id()
|
||||
}
|
||||
|
||||
public var name: String {
|
||||
return _name()
|
||||
_name()
|
||||
}
|
||||
|
||||
public var algorithm: Algorithm {
|
||||
_algorithm()
|
||||
}
|
||||
|
||||
public var keySize: Int {
|
||||
_keySize()
|
||||
}
|
||||
|
||||
public var publicKey: Data {
|
||||
return _publicKey()
|
||||
_publicKey()
|
||||
}
|
||||
|
||||
public static func == (lhs: AnySecret, rhs: AnySecret) -> Bool {
|
||||
|
|
|
@ -8,13 +8,13 @@ public struct OpenSSHKeyWriter {
|
|||
}
|
||||
|
||||
public func data<SecretType: Secret>(secret: SecretType) -> Data {
|
||||
lengthAndData(of: Constants.curveType.data(using: .utf8)!) +
|
||||
lengthAndData(of: Constants.curveIdentifier.data(using: .utf8)!) +
|
||||
lengthAndData(of: curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!) +
|
||||
lengthAndData(of: curveIdentifier(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!) +
|
||||
lengthAndData(of: secret.publicKey)
|
||||
}
|
||||
|
||||
public func openSSHString<SecretType: Secret>(secret: SecretType) -> String {
|
||||
"\(Constants.curveType) \(data(secret: secret).base64EncodedString())"
|
||||
"\(curveType(for: secret.algorithm, length: secret.keySize)) \(data(secret: secret).base64EncodedString())"
|
||||
}
|
||||
|
||||
public func openSSHFingerprint<SecretType: Secret>(secret: SecretType) -> String {
|
||||
|
@ -33,14 +33,21 @@ extension OpenSSHKeyWriter {
|
|||
return Data(bytes: &endian, count: UInt32.bitWidth/8) + data
|
||||
}
|
||||
|
||||
public func readData() {}
|
||||
public func curveIdentifier(for algorithm: Algorithm, length: Int) -> String {
|
||||
switch algorithm {
|
||||
case .ellipticCurve:
|
||||
return "nistp" + String(describing: length)
|
||||
case .rsa:
|
||||
return "ssh-rsa"
|
||||
}
|
||||
}
|
||||
|
||||
extension OpenSSHKeyWriter {
|
||||
|
||||
public enum Constants {
|
||||
public static let curveIdentifier = "nistp256"
|
||||
public static let curveType = "ecdsa-sha2-nistp256"
|
||||
public func curveType(for algorithm: Algorithm, length: Int) -> String {
|
||||
switch algorithm {
|
||||
case .ellipticCurve:
|
||||
return "ecdsa-sha2-nistp" + String(describing: length)
|
||||
case .rsa:
|
||||
return "ssh-rsa"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,23 @@
|
|||
public protocol Secret: Identifiable, Hashable {
|
||||
|
||||
var name: String { get }
|
||||
var algorithm: Algorithm { get }
|
||||
var keySize: Int { get }
|
||||
var publicKey: Data { get }
|
||||
|
||||
}
|
||||
|
||||
public enum Algorithm {
|
||||
case ellipticCurve, rsa
|
||||
public init(secAttr: NSNumber) {
|
||||
let secAttrString = secAttr.stringValue as CFString
|
||||
switch secAttrString {
|
||||
case kSecAttrKeyTypeEC:
|
||||
self = .ellipticCurve
|
||||
case kSecAttrKeyTypeRSA:
|
||||
self = .rsa
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ extension SecureEnclave {
|
|||
|
||||
public let id: Data
|
||||
public let name: String
|
||||
public let algorithm = Algorithm.ellipticCurve
|
||||
public let keySize = 256
|
||||
public let publicKey: Data
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ extension SmartCard {
|
|||
|
||||
public let id: Data
|
||||
public let name: String
|
||||
public let algorithm: Algorithm
|
||||
public let keySize: Int
|
||||
public let publicKey: Data
|
||||
|
||||
}
|
||||
|
|
|
@ -61,7 +61,18 @@ extension SmartCard {
|
|||
}
|
||||
let key = untypedSafe as! SecKey
|
||||
var signError: SecurityError?
|
||||
guard let signature = SecKeyCreateSignature(key, .ecdsaSignatureMessageX962SHA256, data as CFData, &signError) else {
|
||||
let signatureAlgorithm: SecKeyAlgorithm
|
||||
switch (secret.algorithm, secret.keySize) {
|
||||
case (.ellipticCurve, 256):
|
||||
signatureAlgorithm = .ecdsaSignatureMessageX962SHA256
|
||||
case (.ellipticCurve, 384):
|
||||
signatureAlgorithm = .ecdsaSignatureMessageX962SHA384
|
||||
case (.rsa, _):
|
||||
signatureAlgorithm = .rsaSignatureRaw
|
||||
default:
|
||||
fatalError()
|
||||
}
|
||||
guard let signature = SecKeyCreateSignature(key, signatureAlgorithm, data as CFData, &signError) else {
|
||||
throw SigningError(error: signError)
|
||||
}
|
||||
return signature as Data
|
||||
|
@ -90,8 +101,6 @@ extension SmartCard.Store {
|
|||
guard let tokenID = tokenID else { return }
|
||||
let attributes = [
|
||||
kSecClass: kSecClassKey,
|
||||
kSecAttrKeyType: kSecAttrKeyTypeEC,
|
||||
kSecAttrKeySizeInBits: 256,
|
||||
kSecAttrTokenID: tokenID,
|
||||
kSecReturnRef: true,
|
||||
kSecMatchLimit: kSecMatchLimitAll,
|
||||
|
@ -103,11 +112,13 @@ extension SmartCard.Store {
|
|||
let wrapped: [SmartCard.Secret] = typed.map {
|
||||
let name = $0[kSecAttrLabel] as? String ?? "Unnamed"
|
||||
let tokenID = $0[kSecAttrApplicationLabel] as! Data
|
||||
let algorithm = Algorithm(secAttr: $0[kSecAttrKeyType] as! NSNumber)
|
||||
let keySize = $0[kSecAttrKeySizeInBits] as! Int
|
||||
let publicKeyRef = $0[kSecValueRef] as! SecKey
|
||||
let publicKeySecRef = SecKeyCopyPublicKey(publicKeyRef)!
|
||||
let publicKeyAttributes = SecKeyCopyAttributes(publicKeySecRef) as! [CFString: Any]
|
||||
let publicKey = publicKeyAttributes[kSecValueData] as! Data
|
||||
return SmartCard.Secret(id: tokenID, name: name, publicKey: publicKey)
|
||||
return SmartCard.Secret(id: tokenID, name: name, algorithm: algorithm, keySize: keySize, publicKey: publicKey)
|
||||
}
|
||||
secrets.append(contentsOf: wrapped)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ extension Preview {
|
|||
|
||||
let id = UUID().uuidString
|
||||
let name: String
|
||||
let algorithm = Algorithm.ellipticCurve
|
||||
let keySize = 256
|
||||
let publicKey = UUID().uuidString.data(using: .utf8)!
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue