Skip to content

Instantly share code, notes, and snippets.

@notcome
Created April 10, 2018 01:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save notcome/6dc8c0386d8804311a7b7a0b90b08e1a to your computer and use it in GitHub Desktop.
Save notcome/6dc8c0386d8804311a7b7a0b90b08e1a to your computer and use it in GitHub Desktop.
Read and write RSA keys using Keychain Services
import Foundation
import CoreFoundation
import Security
/*
* Following operations will be supported:
* - generate a new keypair
* - export an existing keypair in PKCS12 format
* - delete an existing keypair
*
* All operations take two obligatory arguments:
* - the path to the keychain file
* - the label for the key.
*
* Since Security and Keychain Access shares the same framework,
* the keychain being accessed must be listed in the search path to operate.
* Use "security list" to automate this step.
*/
func checkStatus(status: OSStatus) {
if (status != errSecSuccess) {
print(SecCopyErrorMessageString(status, nil)!)
exit(-1)
}
}
func openKeychain(path: String) -> SecKeychain? {
var keychain: SecKeychain? = nil
var status: OSStatus = errSecSuccess
status = SecKeychainOpen(path, &keychain)
checkStatus(status: status)
return keychain
}
func deleteKey(keychain path: String, label: String) {
let keychain = openKeychain(path: path)
var query: [String: Any] = [kSecClass as String: kSecClassKey,
kSecAttrLabel as String: label,
kSecUseKeychain as String: keychain as Any]
query[kSecAttrKeyClass as String] = kSecAttrKeyClassPrivate
checkStatus(status: SecItemDelete(query as CFDictionary))
query[kSecAttrKeyClass as String] = kSecAttrKeyClassPublic
checkStatus(status: SecItemDelete(query as CFDictionary))
}
func exportPrivateKey(keychain path: String, label: String) {
let keychain = openKeychain(path: path)
let query: [String: Any] = [kSecClass as String: kSecClassKey,
kSecAttrLabel as String: label,
kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
kSecUseKeychain as String: keychain as Any]
var item: CFTypeRef?
checkStatus(status: SecItemCopyMatching(query as CFDictionary, &item))
var data: CFData?
var exportParams = SecItemImportExportKeyParameters()
exportParams.flags = SecKeyImportExportFlags.securePassphrase
checkStatus(status: SecItemExport(item!, .formatPKCS12, .pemArmour, &exportParams, &data))
try! (data! as Data).write(to: URL(fileURLWithPath: "/tmp/new.p12"))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment