mirror of
https://github.com/maxgoedjen/secretive.git
synced 2024-11-25 06:57:07 +00:00
Merge pull request #29 from maxgoedjen/differentalgorithims
Support different EC variants
This commit is contained in:
commit
8853b2ec6d
@ -65,7 +65,7 @@ extension Agent {
|
|||||||
for secret in secrets {
|
for secret in secrets {
|
||||||
let keyBlob = writer.data(secret: secret)
|
let keyBlob = writer.data(secret: secret)
|
||||||
keyData.append(writer.lengthAndData(of: keyBlob))
|
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))
|
keyData.append(writer.lengthAndData(of: curveData))
|
||||||
}
|
}
|
||||||
os_log(.debug, "Agent enumerated %@ identities", secrets.count as NSNumber)
|
os_log(.debug, "Agent enumerated %@ identities", secrets.count as NSNumber)
|
||||||
@ -92,13 +92,24 @@ extension Agent {
|
|||||||
let derSignature = try store.sign(data: dataToSign, with: secret)
|
let derSignature = try store.sign(data: dataToSign, with: secret)
|
||||||
// TODO: Move this
|
// TODO: Move this
|
||||||
notifier.notify(accessTo: secret)
|
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)
|
// 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 rawRepresentation: Data
|
||||||
let r = signature.rawRepresentation[0..<rawLength]
|
switch (secret.algorithm, secret.keySize) {
|
||||||
let s = signature.rawRepresentation[rawLength...]
|
case (.ellipticCurve, 256):
|
||||||
|
rawRepresentation = try CryptoKit.P256.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation
|
||||||
|
case (.ellipticCurve, 384):
|
||||||
|
rawRepresentation = try CryptoKit.P384.Signing.ECDSASignature(derRepresentation: derSignature).rawRepresentation
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let rawLength = rawRepresentation.count/2
|
||||||
|
let r = rawRepresentation[0..<rawLength]
|
||||||
|
let s = rawRepresentation[rawLength...]
|
||||||
|
|
||||||
var signatureChunk = Data()
|
var signatureChunk = Data()
|
||||||
signatureChunk.append(writer.lengthAndData(of: r))
|
signatureChunk.append(writer.lengthAndData(of: r))
|
||||||
|
@ -6,6 +6,8 @@ public struct AnySecret: Secret {
|
|||||||
fileprivate let hashable: AnyHashable
|
fileprivate let hashable: AnyHashable
|
||||||
fileprivate let _id: () -> AnyHashable
|
fileprivate let _id: () -> AnyHashable
|
||||||
fileprivate let _name: () -> String
|
fileprivate let _name: () -> String
|
||||||
|
fileprivate let _algorithm: () -> Algorithm
|
||||||
|
fileprivate let _keySize: () -> Int
|
||||||
fileprivate let _publicKey: () -> Data
|
fileprivate let _publicKey: () -> Data
|
||||||
|
|
||||||
public init<T>(_ secret: T) where T: Secret {
|
public init<T>(_ secret: T) where T: Secret {
|
||||||
@ -14,26 +16,38 @@ public struct AnySecret: Secret {
|
|||||||
hashable = secret.hashable
|
hashable = secret.hashable
|
||||||
_id = secret._id
|
_id = secret._id
|
||||||
_name = secret._name
|
_name = secret._name
|
||||||
|
_algorithm = secret._algorithm
|
||||||
|
_keySize = secret._keySize
|
||||||
_publicKey = secret._publicKey
|
_publicKey = secret._publicKey
|
||||||
} else {
|
} else {
|
||||||
base = secret as Any
|
base = secret as Any
|
||||||
self.hashable = secret
|
self.hashable = secret
|
||||||
_id = { secret.id as AnyHashable }
|
_id = { secret.id as AnyHashable }
|
||||||
_name = { secret.name }
|
_name = { secret.name }
|
||||||
|
_algorithm = { secret.algorithm }
|
||||||
|
_keySize = { secret.keySize }
|
||||||
_publicKey = { secret.publicKey }
|
_publicKey = { secret.publicKey }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var id: AnyHashable {
|
public var id: AnyHashable {
|
||||||
return _id()
|
_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
public var name: String {
|
public var name: String {
|
||||||
return _name()
|
_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
public var algorithm: Algorithm {
|
||||||
|
_algorithm()
|
||||||
|
}
|
||||||
|
|
||||||
|
public var keySize: Int {
|
||||||
|
_keySize()
|
||||||
}
|
}
|
||||||
|
|
||||||
public var publicKey: Data {
|
public var publicKey: Data {
|
||||||
return _publicKey()
|
_publicKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func == (lhs: AnySecret, rhs: AnySecret) -> Bool {
|
public static func == (lhs: AnySecret, rhs: AnySecret) -> Bool {
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
|
|
||||||
// For the moment, only supports ecdsa-sha2-nistp256 keys
|
// For the moment, only supports ecdsa-sha2-nistp256 and ecdsa-sha2-nistp386 keys
|
||||||
public struct OpenSSHKeyWriter {
|
public struct OpenSSHKeyWriter {
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func data<SecretType: Secret>(secret: SecretType) -> Data {
|
public func data<SecretType: Secret>(secret: SecretType) -> Data {
|
||||||
lengthAndData(of: Constants.curveType.data(using: .utf8)!) +
|
lengthAndData(of: curveType(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!) +
|
||||||
lengthAndData(of: Constants.curveIdentifier.data(using: .utf8)!) +
|
lengthAndData(of: curveIdentifier(for: secret.algorithm, length: secret.keySize).data(using: .utf8)!) +
|
||||||
lengthAndData(of: secret.publicKey)
|
lengthAndData(of: secret.publicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func openSSHString<SecretType: Secret>(secret: SecretType) -> String {
|
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 {
|
public func openSSHFingerprint<SecretType: Secret>(secret: SecretType) -> String {
|
||||||
@ -33,14 +33,17 @@ extension OpenSSHKeyWriter {
|
|||||||
return Data(bytes: &endian, count: UInt32.bitWidth/8) + data
|
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:
|
||||||
extension OpenSSHKeyWriter {
|
return "nistp" + String(describing: length)
|
||||||
|
}
|
||||||
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
public protocol Secret: Identifiable, Hashable {
|
public protocol Secret: Identifiable, Hashable {
|
||||||
|
|
||||||
var name: String { get }
|
var name: String { get }
|
||||||
|
var algorithm: Algorithm { get }
|
||||||
|
var keySize: Int { get }
|
||||||
var publicKey: Data { get }
|
var publicKey: Data { get }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Algorithm {
|
||||||
|
case ellipticCurve
|
||||||
|
public init(secAttr: NSNumber) {
|
||||||
|
let secAttrString = secAttr.stringValue as CFString
|
||||||
|
switch secAttrString {
|
||||||
|
case kSecAttrKeyTypeEC:
|
||||||
|
self = .ellipticCurve
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,8 @@ extension SecureEnclave {
|
|||||||
|
|
||||||
public let id: Data
|
public let id: Data
|
||||||
public let name: String
|
public let name: String
|
||||||
|
public let algorithm = Algorithm.ellipticCurve
|
||||||
|
public let keySize = 256
|
||||||
public let publicKey: Data
|
public let publicKey: Data
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ extension SmartCard {
|
|||||||
|
|
||||||
public let id: Data
|
public let id: Data
|
||||||
public let name: String
|
public let name: String
|
||||||
|
public let algorithm: Algorithm
|
||||||
|
public let keySize: Int
|
||||||
public let publicKey: Data
|
public let publicKey: Data
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,16 @@ extension SmartCard {
|
|||||||
}
|
}
|
||||||
let key = untypedSafe as! SecKey
|
let key = untypedSafe as! SecKey
|
||||||
var signError: SecurityError?
|
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
|
||||||
|
default:
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
guard let signature = SecKeyCreateSignature(key, signatureAlgorithm, data as CFData, &signError) else {
|
||||||
throw SigningError(error: signError)
|
throw SigningError(error: signError)
|
||||||
}
|
}
|
||||||
return signature as Data
|
return signature as Data
|
||||||
@ -90,9 +99,8 @@ extension SmartCard.Store {
|
|||||||
guard let tokenID = tokenID else { return }
|
guard let tokenID = tokenID else { return }
|
||||||
let attributes = [
|
let attributes = [
|
||||||
kSecClass: kSecClassKey,
|
kSecClass: kSecClassKey,
|
||||||
kSecAttrKeyType: kSecAttrKeyTypeEC,
|
|
||||||
kSecAttrKeySizeInBits: 256,
|
|
||||||
kSecAttrTokenID: tokenID,
|
kSecAttrTokenID: tokenID,
|
||||||
|
kSecAttrKeyType: kSecAttrKeyTypeEC, // Restrict to EC
|
||||||
kSecReturnRef: true,
|
kSecReturnRef: true,
|
||||||
kSecMatchLimit: kSecMatchLimitAll,
|
kSecMatchLimit: kSecMatchLimitAll,
|
||||||
kSecReturnAttributes: true
|
kSecReturnAttributes: true
|
||||||
@ -103,11 +111,13 @@ extension SmartCard.Store {
|
|||||||
let wrapped: [SmartCard.Secret] = typed.map {
|
let wrapped: [SmartCard.Secret] = typed.map {
|
||||||
let name = $0[kSecAttrLabel] as? String ?? "Unnamed"
|
let name = $0[kSecAttrLabel] as? String ?? "Unnamed"
|
||||||
let tokenID = $0[kSecAttrApplicationLabel] as! Data
|
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 publicKeyRef = $0[kSecValueRef] as! SecKey
|
||||||
let publicKeySecRef = SecKeyCopyPublicKey(publicKeyRef)!
|
let publicKeySecRef = SecKeyCopyPublicKey(publicKeyRef)!
|
||||||
let publicKeyAttributes = SecKeyCopyAttributes(publicKeySecRef) as! [CFString: Any]
|
let publicKeyAttributes = SecKeyCopyAttributes(publicKeySecRef) as! [CFString: Any]
|
||||||
let publicKey = publicKeyAttributes[kSecValueData] as! Data
|
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)
|
secrets.append(contentsOf: wrapped)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ extension Preview {
|
|||||||
|
|
||||||
let id = UUID().uuidString
|
let id = UUID().uuidString
|
||||||
let name: String
|
let name: String
|
||||||
|
let algorithm = Algorithm.ellipticCurve
|
||||||
|
let keySize = 256
|
||||||
let publicKey = UUID().uuidString.data(using: .utf8)!
|
let publicKey = UUID().uuidString.data(using: .utf8)!
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user