Created
December 3, 2018 22:30
-
-
Save rickmark/897c65106db34ac7f4cf246ae988e3b3 to your computer and use it in GitHub Desktop.
Mashing OpenSSL and Keychain
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private func getKeychainCopy() -> (URL, SecKeychain) { | |
let tempDirectoryURL = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true) | |
let tempKeychainFile = tempDirectoryURL.appendingPathComponent("\(UUID().uuidString)-demo.keychain") | |
var keychain: SecKeychain? | |
assert(SecKeychainCreate(tempKeychainFile.absoluteString.toUnixPath(), 0, "", false, nil, &keychain) == kOSReturnSuccess) | |
var privateKey: SecKey! | |
var publicKey: SecKey! | |
let tag = "com.dropbox.entsec.certificate-sync.tests".data(using: .utf8)! | |
let generationAttributes: [String: Any] = [ | |
kSecAttrKeyType as String: kSecAttrKeyTypeRSA, | |
kSecAttrKeySizeInBits as String: 4096, | |
kSecPrivateKeyAttrs as String: [ | |
kSecAttrIsPermanent as String: true, | |
kSecAttrApplicationTag as String: tag | |
] | |
] | |
assert(SecKeyGeneratePair(generationAttributes as CFDictionary, &publicKey, &privateKey) == kOSReturnSuccess) | |
let storePublicKey: [String: Any] = [ | |
kSecClass as String: kSecClassKey, | |
kSecAttrApplicationTag as String: "\(tag).public", | |
kSecValueRef as String: publicKey!, | |
kSecUseKeychain as String: keychain! | |
] | |
let storePrivateKey: [String: Any] = [ | |
kSecClass as String: kSecClassKey, | |
kSecAttrApplicationTag as String: tag, | |
kSecValueRef as String: privateKey!, | |
kSecUseKeychain as String: keychain! | |
] | |
var publicKeyResult: CFTypeRef? | |
var privateKeyResult: CFTypeRef? | |
assert(SecItemAdd(storePublicKey as CFDictionary, &publicKeyResult) == kOSReturnSuccess) | |
assert(SecItemAdd(storePrivateKey as CFDictionary, &privateKeyResult) == kOSReturnSuccess) | |
privateKey = (privateKeyResult! as! SecKey) | |
publicKey = (publicKeyResult! as! SecKey) | |
var privateKeyPem: CFData? | |
var exportKeyParameters = SecItemImportExportKeyParameters() | |
assert(SecItemExport(privateKey, SecExternalFormat.formatPEMSequence, SecItemImportExportFlags(), &exportKeyParameters, &privateKeyPem) == kOSReturnSuccess) | |
var privateKeyMarshaledData = privateKeyPem! as Data | |
let keyBasicIO = privateKeyMarshaledData.withUnsafeBytes { (data) -> UnsafeMutablePointer<BIO>? in | |
return BIO_new_mem_buf(data, Int32(privateKeyMarshaledData.count)) | |
} | |
let openSSLPrivateKey = PEM_read_bio_PrivateKey(keyBasicIO!, nil, nil, nil) | |
BIO_free(keyBasicIO) | |
assert(openSSLPrivateKey != nil) | |
let certificate = X509_new() | |
assert(X509_set_version(certificate, 2) == 1) | |
assert(ASN1_INTEGER_set(X509_get_serialNumber(certificate), 1) == 1) | |
let currentTime = timegm(nil) | |
var notBefore = ASN1_TIME() | |
var notAfter = ASN1_TIME() | |
assert(ASN1_TIME_set(¬Before, currentTime) != nil) | |
assert(ASN1_TIME_adj(¬After, currentTime, 365, 0) != nil) | |
assert(X509_set_notBefore(certificate!, ¬Before) == 1) | |
assert(X509_set_notAfter(certificate!, ¬After) == 1) | |
let name = X509_NAME_new() | |
assert(X509_NAME_add_entry_by_txt(name, "CN", V_ASN1_IA5STRING, "Self Signed Test Certificate", -1, -1, 0) == 1) | |
assert(X509_set_subject_name(certificate!, name) == 1) | |
assert(X509_set_issuer_name(certificate!, name) == 1) | |
assert(X509_set_pubkey(certificate!, openSSLPrivateKey) == 1) | |
assert(X509_sign(certificate!, openSSLPrivateKey, EVP_sha256()) != 0) | |
let certificatePEM = BIO_new(BIO_s_mem()) | |
assert(PEM_write_bio_X509(certificatePEM, certificate!) != 0) | |
var data: UnsafeMutableRawPointer? | |
let dataSize = BIO_ctrl(certificatePEM, BIO_CTRL_INFO, 0, &data) | |
assert(dataSize > 0) | |
assert(data != nil) | |
let certificateData = Data(bytes: data!, count: dataSize) | |
X509_NAME_free(name) | |
X509_free(certificate) | |
EVP_PKEY_free(openSSLPrivateKey) | |
BIO_free(certificatePEM) | |
var certificateImportResults: CFArray? | |
var importItemType = SecExternalItemType.itemTypeCertificate | |
assert(SecItemImport(certificateData as CFData, nil, nil, &importItemType, SecItemImportExportFlags(rawValue: 0), nil, keychain!, &certificateImportResults) == kOSReturnSuccess) | |
var identity: SecIdentity? | |
let certificateKeychainItem = (certificateImportResults as! [ SecCertificate ]).first! | |
assert(SecIdentityCreateWithCertificate(keychain!, certificateKeychainItem, &identity) == kOSReturnSuccess) | |
return (tempKeychainFile, keychain!) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment