Skip to content

Commit

Permalink
Server Keys
Browse files Browse the repository at this point in the history
  • Loading branch information
consuelita committed Dec 22, 2018
1 parent 896d309 commit 4c91f60
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Sources/ReplicantSwift/Polish/PolishClientModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class PolishClientModel
return nil
}

guard let newKeyPair = controller.generateKeyPair()
guard let newKeyPair = controller.generateKeyPair(withAttributes: controller.generateKeyAttributesDictionary())
else
{
return nil
Expand Down
83 changes: 79 additions & 4 deletions Sources/ReplicantSwift/Polish/PolishController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public struct PolishController
{
let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
let polishTag = "org.operatorfoundation.replicant.polish".data(using: .utf8)!
let polishServerTag = "org.operatorfoundation.replicant.polishServer".data(using: .utf8)!

/// Decode data to get public key. This only decodes key data that is NOT padded.
public func decodeKey(fromData publicKeyData: Data) -> SecKey?
Expand All @@ -34,11 +35,11 @@ public struct PolishController
return decodedPublicKey
}

public func generatePrivateKey() -> SecKey?
public func generatePrivateKey(withAttributes attributes: CFDictionary) -> SecKey?
{
// Generate private key
var error: Unmanaged<CFError>?
let attributes = self.generateKeyAttributesDictionary()
//let attributes = self.generateKeyAttributesDictionary()

guard let privateKey = SecKeyCreateRandomKey(attributes, &error)
else
Expand All @@ -62,9 +63,9 @@ public struct PolishController
return publicKey
}

func generateKeyPair() -> (privateKey: SecKey, publicKey: SecKey)?
func generateKeyPair(withAttributes attributes: CFDictionary) -> (privateKey: SecKey, publicKey: SecKey)?
{
guard let privateKey = generatePrivateKey()
guard let privateKey = generatePrivateKey(withAttributes: attributes)
else
{
return nil
Expand All @@ -79,6 +80,45 @@ public struct PolishController
return (privateKey, publicKey)
}

func fetchOrCreateServerKeyPair() ->(privateKey: SecKey, publicKey: SecKey)?
{

// Do we already have a key?
var item: CFTypeRef?
let status = SecItemCopyMatching(generateServerKeySearchQuery(), &item)

switch status
{
case errSecItemNotFound:
// We don't?
// Let's create some and return those
return generateKeyPair(withAttributes: generateServerKeyAttributesDictionary())
case errSecSuccess:
// Return the pair
guard let itemDictionary = item as? [String: Any]
else
{
print("Received unexpected key data.")
return nil
}

// FIXME: Casting issues here
let privateKey = itemDictionary[kSecValueRef as String] as! SecKey
guard let publicKey = generatePublicKey(usingPrivateKey: privateKey)
else
{
print("Unable to generate a public key uding the provided private key.")
return nil
}

return (privateKey, publicKey)

default:
print("\nReceived an unexpacted response while checking for an existing server key: \(status)\n")
return nil
}
}

func deleteKeys()
{
//Remove client keys from secure enclave
Expand Down Expand Up @@ -110,6 +150,41 @@ public struct PolishController
return attributes as CFDictionary
}

func generateServerKeyAttributesDictionary() -> CFDictionary
{
let access = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleAlwaysThisDeviceOnly,
.privateKeyUsage,
nil)!

let privateKeyAttributes: [String: Any] = [
kSecAttrIsPermanent as String: true,
kSecAttrApplicationTag as String: polishServerTag,
//kSecAttrAccessControl as String: access
]

let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits as String: 256,
//kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs as String: privateKeyAttributes
]

return attributes as CFDictionary
}

func generateServerKeySearchQuery() -> CFDictionary
{
let query: [String: Any] = [kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: polishServerTag,
kSecMatchLimit as String: kSecMatchLimitOne,
kSecReturnRef as String: true,
kSecReturnAttributes as String: false,
kSecReturnData as String: false]

return query as CFDictionary
}

/// This is the format needed to send the key to the server.
public func generateAndEncryptPaddedKeyData(fromKey key: SecKey, withChunkSize chunkSize: Int, usingServerKey serverKey: SecKey) -> Data?
{
Expand Down
7 changes: 4 additions & 3 deletions Sources/ReplicantSwift/Polish/PolishServerModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ public class PolishServerModel

public init?(clientPublicKeyData: Data? = nil)
{
controller.deleteKeys()

// The client's key if we get one on init
if let publicKeyData = clientPublicKeyData
{
if let cPublicKey = controller.decodeKey(fromData: publicKeyData)
Expand All @@ -28,7 +27,9 @@ public class PolishServerModel
}
}

guard let newKeyPair = controller.generateKeyPair()
// Check to see if the server already has a keypair first
// If not, create one.
guard let newKeyPair = controller.fetchOrCreateServerKeyPair()
else
{
return nil
Expand Down

0 comments on commit 4c91f60

Please sign in to comment.