Generate a Csr in iOS Library

Generate a CSR in iOS Library?

Yes, it is possible but is not simple at all because iOS do not work with standard formats for keys as you could think

Generate CSR as PEM

I have used this library successfully to generate a CSR in PCKS#10 format with a key generated in KeyChain and encoded in DER format (binary).

https://github.com/ateska/ios-csr

func createCertificationRequest(keyId: String, C: String?, CN: String?, O:String?, SERIALNAME:String? ) -> String {

//Replace this with your mechanism to get the private and public key
let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId)
let privateKey = loadKeySecKeyFromKeyChain(PRIVATE_KEY + keyId)

//SCCSR from ios-csr library
let sccsr : SCCSR = SCCSR()

sccsr.commonName = CN;
sccsr.organizationName = O;
sccsr.countryName = C;

// // aditional data you can set
// sccsr.countryName = @"";
// sccsr.organizationalUnitName = @"";
// sccsr.subjectDER = nil;
// //
//
let certificateRequest = sccsr.build(publicKey, privateKey: privateKey)
let certificateRequestB64 = certificateRequest.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())

let certificateRequestPEM =
"-----BEGIN CERTIFICATE REQUEST-----\\n" + certificateRequestB64 + "\\n-----END CERTIFICATE REQUEST-----\\n"

return certificateRequestPEM

}

After this, you can send the CSR to server in DER (format) or encode in PEM format (base64) depending of the capabilities of your serv

I guess you are missed the final step, returning the X509 from server to device to be stored

EDITED

Generating keys with KeyChain

I include also the code to help generating keys using iOS-KeyChain

let KEY_SIZE = 2048
let PUBLIC_KEY = "mysystem.publickey."
let PRIVATE_KEY = "mysystem.privatekey."

// Generates a key pair in KeyChain using keyId as identifier and returns the public key
// publicKey -->PUBLIC_KEY + keyId
// privateKey --> PRIVATE_KEY + keyId
// KEY_SIZE is stablished globally
func generateKeyPairInKeyChain(keyId: String) -> String {

let privateAttributes = [String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): PRIVATE_KEY + keyId,
String(kSecAttrIsPermanent): kCFBooleanTrue]
let publicAttributes = [String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): PUBLIC_KEY + keyId,
String(kSecAttrIsPermanent): kCFBooleanTrue]

let pairAttributes = [String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): KEY_SIZE,
String(kSecPublicKeyAttrs): publicAttributes,
String(kSecPrivateKeyAttrs): privateAttributes]

//Ensure that keychain has no key with keyId identifier
deleteKeyPairFromKeyChain(keyId)

var publicRef: SecKeyRef?
var privateRef: SecKeyRef?

//Generate the keys and recover the references in publicRef and privateRf
switch SecKeyGeneratePair(pairAttributes, &publicRef, &privateRef) {
case noErr:
// Get the public key as a String
let publicKeyStr = loadKeyStringFromKeyChain(PUBLIC_KEY + keyId)
return publicKeyStr
default:
return ""
}
}

Utilities

The following includes the utility functions used generating CSR or keys. You will see that are basically the same changing the type of result (some extra work is needed to simplify...)

//Delete an existing keypair from keychain (public + private)
func deleteKeyPairFromKeyChain(keyId: String) {
deleteRSAKeyFromKeychain(PRIVATE_KEY + keyId)
deleteRSAKeyFromKeychain(PUBLIC_KEY + keyId)
}

// Delete existing RSA key from keychain
private func deleteRSAKeyFromKeychain(tagName: String) {
let queryFilter: [String: AnyObject] = [
String(kSecClass) : kSecClassKey,
String(kSecAttrKeyType) : kSecAttrKeyTypeRSA,
String(kSecAttrApplicationTag): tagName
]
let status: OSStatus = SecItemDelete(queryFilter)
NSLog("private or public deletion result is: " + status.description)
}

// Finds the SecKeyRef corresponding to the parameter key and returns it as a String
private func loadKeyStringFromKeyChain(key: String) -> String {
let query: Dictionary<String, AnyObject> = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): KEY_SIZE,
String(kSecClass): kSecClassKey,
String(kSecAttrApplicationTag): key,
kSecReturnData as String : kCFBooleanTrue ]

var dataTypeRef: AnyObject? = nil
var resultData: NSData? = nil

let status: OSStatus = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query as NSDictionary, UnsafeMutablePointer($0)) }
NSLog("SecItemCopyMatching: " + status.description)

if status == errSecSuccess {
NSLog("private or public debug description is: " + dataTypeRef.debugDescription)
resultData = dataTypeRef as? NSData
let resultStr = resultData?.base64EncodedStringWithOptions([])
NSLog("private or public String is: " + resultStr!)
return resultStr!
} else {
NSLog("no key found!!!!")
return ""
}
}

// Finds the SecKeyRef corresponding to the parameter key and returns it
func loadKeySecKeyFromKeyChain(key: String) -> SecKeyRef {
let query: Dictionary<String, AnyObject> = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): KEY_SIZE,
String(kSecClass): kSecClassKey,
String(kSecAttrApplicationTag): key,
kSecReturnRef as String : kCFBooleanTrue ]

var dataTypeRef: Unmanaged<AnyObject>? = nil
var resultData: SecKeyRef? = nil

let status: OSStatus = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query as NSDictionary, UnsafeMutablePointer($0)) }
NSLog("SecItemCopyMatching: " + status.description)

if status == errSecSuccess {
NSLog("private or public debug description is: " + dataTypeRef.debugDescription)
resultData = (dataTypeRef!.takeRetainedValue() as! SecKeyRef)
NSLog("SecItemCopyMatching returns SecKey: " + resultData.debugDescription)
return resultData!
} else {
return resultData!
}
}

// Finds the SecKeyRef corresponding to the parameter key and returns it as a NSData
private func loadKeyStringFromKeyChainAsNSData(key: String) -> NSData {
let query: Dictionary<String, AnyObject> = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): KEY_SIZE,
String(kSecClass): kSecClassKey,
String(kSecAttrApplicationTag): key,
kSecReturnData as String : kCFBooleanTrue ]

var dataTypeRef: AnyObject? = nil
var resultData: NSData? = nil

let status: OSStatus = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query as NSDictionary, UnsafeMutablePointer($0)) }
NSLog("SecItemCopyMatching: " + status.description)

if status == errSecSuccess {
NSLog("private or public debug description is: " + dataTypeRef.debugDescription)
resultData = dataTypeRef as? NSData
return resultData!
} else {
NSLog("no key found!!!!")
return resultData!
}
}

EDITED

Export public key as DER

Note that this code will not provide the publickey in a readable format like DER

let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId)

If you need to use the public key outside iOS (or importing a certificate and obtaining a valid key), extra actions are needed. Converting keys are supported using CryptoExportImportManager.swift of the following project

https://github.com/DigitalLeaves/CryptoExportImportManager

For example

func exportPublicKeyToDER(keyId:String) -> NSData?{

let publicKey = loadKeyStringFromKeyChainAsNSData(PUBLIC_KEY + keyId)
let keyType = kSecAttrKeyTypeRSA
let keySize = 2048
let exportImportManager = CryptoExportImportManager()
if let exportableDERKey = exportImportManager.exportPublicKeyToDER(publicKey, keyType: keyType as String, keySize: keySize) {
return exportableDERKey
} else {
return nil
}
}

Is it possible to generate certificate signing request(.csr) using security framework in iOS?

There is no explicit support for CSR in Security Framework in iOS. However, it is not that difficult to build CSR 'manually' - it is just ASN.1 DER block of data that are available at iOS runtime.

Here is pseudo code of that:

  1. Use SecKeyGeneratePair() from Security Framework to create fresh public/private key
  2. Implement getPublicKeyBits method to retrieve NSData-form of fresh public key (see https://developer.apple.com/library/ios/samplecode/CryptoExercise/Introduction/Intro.html )
  3. Implement getPrivateKey method to retrieve SecKeyRef from Keychain
  4. Follow http://www.ietf.org/rfc/rfc2986.txt to construct ASN.1 DER of CSR in NSMutableData
  5. Use CC_SHA1_* to create signature hash of Certification Request Info (part of CSR)
  6. Use SecKeyRawSign and private key to sign CSR

This will create proper CSR (in form of NSData) that can be sent to CA for approval.

My implementation is available on GitHub: http://github.com/ateska/ios-csr .

How to obtain Certificate Signing Request

Since you installed a new OS you probably don't have any more of your private and public keys that you used to sign your app in to XCode before. You need to regenerate those keys on your machine by revoking your previous certificate and asking for a new one on the iOS development portal. As part of the process you will be asked to generate a Certificate Signing Request which is where you seem to have a problem.

You will find all you need there which consists of (from the official doc):

1.Open Keychain Access on your Mac (located in Applications/Utilities).

2.Open Preferences and click Certificates. Make sure both Online Certificate Status Protocol and Certificate Revocation List are set to
Off.

3.Choose Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority.

Note: If you have a private key selected when you do this, the CSR
won’t be accepted. Make sure no private key is selected. Enter your
user email address and common name. Use the same address and name as
you used to register in the iOS Developer Program. No CA Email Address
is required.

4.Select the options “Saved to disk” and “Let me specify key pair
information” and click Continue.

5.Specify a filename and click Save. (make sure to replace .certSigningRequest with .csr)

For the Key Size choose 2048 bits and for Algorithm choose RSA. Click
Continue and the Certificate Assistant creates a CSR and saves the
file to your specified location.

Can't create a new Certificate Signing Request(CSR)?

I have solved this question! Here are the steps:

Go to your terminal and type in:

ls -l ~/Library/

This will make sure that the permissions on the keychain folder are correct.

privs on the Keychains folder should be

drwxr-xr-x

If it is not drwxr-xr-x then follow these steps:

  • Go to the drop down menu in Keychain Access.
  • Keychain Access > Keychain First Aid
  • Enter your Username and Password
  • Tick on Repair
  • Click Start

This solved my problem! :)

OSX Keychain Access-Generate CSR from existing Private Key for APNS (Apple Push Notification Service)

When you go into Provisioning Profile to Enable/Configure Push Notifications, the first thing it asks for is a CSR (Code Signing Certificate).

You can generate this with an existing private key from Keychain Access instead of creating a new one.

Just open keychain access and then scroll thru and find a previous PRIVATE KEY (probably called YOUR NAME) and then right-click (two finger click) on it and choose Request A Certificate From A Certificate Authority With "bla bla bla".

I just enter the same email address in both User Email Address and CA Email Address, and choose Saved To Disk.

Then upload that to create your .cer files



Related Topics



Leave a reply



Submit