Supporting different EC sizes, RSA not working yet

This commit is contained in:
Max Goedjen
2020-03-08 22:17:59 -07:00
parent 603d021939
commit 945907cfd4
8 changed files with 94 additions and 24 deletions

View File

@@ -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 {

View File

@@ -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() {}
}
extension OpenSSHKeyWriter {
public enum Constants {
public static let curveIdentifier = "nistp256"
public static let curveType = "ecdsa-sha2-nistp256"
public func curveIdentifier(for algorithm: Algorithm, length: Int) -> String {
switch algorithm {
case .ellipticCurve:
return "nistp" + String(describing: length)
case .rsa:
return "ssh-rsa"
}
}
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"
}
}
}

View File

@@ -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()
}
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}