As far as I can tell, Apple's own security infrastructure does not have an API that is currently exposed to f or generates CSR. It is technically OpenSSL wrapped; so if you have OpenSSL (I personally prefer LibreSSL, libtls makes life easier).
Alternatively, you can also use Commoncrypto, which my answer will not cover, but there are many examples there
So, let's take a look at the steps to figure out how to do this. I found that the easiest way to work with OpenSSL is to completely ignore the documentation and go directly to the reading source.
To achieve what we need, we need to โreplicateโ the following two commands:
openssl ecparam -out server.key -name prime256v1 -genkey
openssl req -new -key server.key -out server.csr
Important Note: Be sure to select a protected curve. Use openssl ecparam -list_curves to get a list of supported curves for your version of openssl. More details
Step 1 Key Creation
ecparam tells us that we need to first view sslsource / apps / openssl / ecparam.c.
The source gives us 3 steps: Set up a BIO for recording, setting up group parameters, and finally creating a key.
Step 2 Create CSR
Following the same principles, but this time looking at req.c and some code in apps.c that contains some boilerplate code used in req.c
I used this method to create a crude but working proof of the concept that works quickly, you can check it on github here: CertificateTool The code will run on any system where you can compile switch4 + toolchain and some version of openSSL.
Edit:
Creating an EC Private Key:
// // ECKey.swift // CertificateToolPackageDescription // // Created by Antwan van Houdt on 10/01/2018. // import CLibreSSL public class ECKey { internal let secretKey: OpaquePointer private let group: OpaquePointer public init() { group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1) EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE) EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_COMPRESSED) secretKey = EC_KEY_new() EC_KEY_set_group(secretKey, group) EC_KEY_generate_key(secretKey) } deinit { EC_KEY_free(secretKey) EC_GROUP_free(group) } }
Create a signature request:
// // CertificateRequest.swift // CertificateToolPackageDescription // // Created by Antwan van Houdt on 10/01/2018. // import CLibreSSL public enum NIDType: String { case email = "emailAddress" case hostName = "CN" case organizationalUnit = "OU" case organization = "O" case city = "L" case state = "ST" case countryCode = "C" } public class CertificateSigningRequest { private let request: UnsafeMutablePointer<X509_REQ> private let key: ECKey private let name: UnsafeMutablePointer<X509_NAME> public init(key: ECKey, email: String, hostName: String, organizationalUnit: String, organization: String, countryCode: String, state: String, city: String) { request = X509_REQ_new() self.key = key name = X509_NAME_new() X509_REQ_set_version(request, 2) self.add(name: email, type: .email) self.add(name: hostName, type: .hostName) self.add(name: organizationalUnit, type: .organizationalUnit) self.add(name: organization, type: .organization) self.add(name: countryCode, type: .countryCode) self.add(name: city, type: .city) self.add(name: state, type: .state) X509_REQ_set_subject_name(request, name) self.setPublicKey() } deinit { X509_REQ_free(request) X509_NAME_free(name) } private func add(name: String, type: NIDType) { var buff = Array(name.utf8) X509_NAME_add_entry_by_NID(self.name, OBJ_txt2nid(type.rawValue), MBSTRING_UTF8, &buff, Int32(buff.count), 0, 0) } private func setPublicKey() { let certKey = EVP_PKEY_new() EVP_PKEY_set1_EC_KEY(certKey, key.secretKey) X509_REQ_set_pubkey(request, certKey) X509_REQ_sign(request, certKey, EVP_sha256()) EVP_PKEY_free(certKey) } }
Note This code does not contain any BIO-related functions (yet) to write PEM data to a file or to a data buffer, but it is very easy to add.
Disclaimer: I am not a professional cryptographer, and I do not know all the features of the OpenSSL API. I cannot guarantee that the code I provided is a 100% correct implementation. Always be careful with code, especially crypto code downloaded from the Internet.