Xamarin iOS: unable save PKCS12 data in the iOS keychain - ios

Use case:
The app imports PKCS 12 file (with cert and private key) and saves it for later use.
Current status:
I was able to use SecImportExport.ImportPkcs12 in order to get SecIdentity and SecTrust objects.
Unfortunately I’m unable to assign SecIdentity and SecTrust object to SecRecord.
The code:
SecIdentity identityObject = ...;
SecTrust trustObject = ...;
SecRecord record = new SecRecord(SecKind.Identity);
record.Account = "Identity";
record.ValueData = ? //HOW TO CONVERT SecIdentity to NSData?
var res = SecKeyChain.Add(record);

You can use the SecRecord.SetValueRef (identityObject) which can be used to store keys (SecKey), certificates (SecCertificate) or identities.

Related

Get EC Private Key PEM string from SecKey Object

I'm trying to get a PEM encoded key from a SecKey on iOS. The EC private key is stored on the Keychain.
I'm getting a Data object from the SecKey object:
if #available(iOS 10.0, *) {
var error: Unmanaged<CFError>?
if let cfdata = SecKeyCopyExternalRepresentation(key, &error) {
return cfdata as Data
}
}
The Data object is in the 04 || X || Y || K format. How do I convert that to a PEM key?
Which curve do you use?
if you use kSecECCurveSecp256r1 and kSecAttrTokenIDSecureEnclave, you can't export the ECPrivateKey! Keys created within a trusted coprocessor cannot he exported (and I believe ones imported can’t either). Plus, you should never transfer private key material. It defeats the entire point of the SEP.
see:
https://developer.apple.com/documentation/security/ksecattrtokenidsecureenclave
https://support.apple.com/en-ng/guide/security/sec59b0b31ff/web

Export SecKey to pkcs8 format

Currently I am generating a RSAKeyPair with the iOS security framework
statusCode = SecKeyGeneratePair(keyPairAttributes as CFDictionary, &newPublicKey, &newPrivateKey)
I then want to export these keys to a PEM format with PKCS8. The standard method apple provides to export keys is this:
let cfData = SecKeyCopyExternalRepresentation(self, &error)
but this data gives me the key in the PKCS1 format. Is there a way to convert the PKCS1 format to PKCS8?
So far all my research left me clueless on what to actually do to convert these formats.
I can't translate into Swift, but here's the nearly-Objective-C:
SecItemImportExportKeyParameters keyParams = {};
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.passphrase = you_need_a_cfstringref_here;
SecExternalFormat dataFormat = kSecFormatWrappedPKCS8;
OSStatus status = SecItemExport(privateKey, dataFormat, 0, &keyParams, &cfData);

Swift 3 export SecKey to String

I am developing an iOS app using swift 3.
I need to export an SecKey (which is the user RSA publickey reference) to a string (e.g base64) in order to share it through a generated QRCode.
It also has to work the other way since the other user that scans the QRCode, will be able to rebuild a SecKey reference from the string extracted from the QRCode.
I found few tutorials but I don't understand exactly what I need to extract from the SecKey reference, and I don't know how to convert it to a String.
Export Key (iOS 10 only)
var error:Unmanaged<CFError>?
if let cfdata = SecKeyCopyExternalRepresentation(publicKey!, &error) {
let data:Data = cfdata as Data
let b64Key = data.base64EncodedString()
}
See https://stackoverflow.com/a/30662270/5276890 and https://stackoverflow.com/a/27935528/5276890 for longer ways which probably support iOS < 10.
Reimport Key
guard let data2 = Data.init(base64Encoded: b64Key) else {
return
}
let keyDict:[NSObject:NSObject] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: NSNumber(value: 512),
kSecReturnPersistentRef: true as NSObject
]
guard let publicKey = SecKeyCreateWithData(data2 as CFData, keyDict as CFDictionary, nil) else {
return
}
Note: This generates a base64 key and not a certificate. A lot of code samples online deal with how to generate a public key from a certificate using SecCertificateCreateWithData
Also: 512 bit is fast to generate but worthless. Pick a longer and secure value once you're satisfied with the results.
I got valid results back when importing the key I generated and exported, so I assume it works, but I did not try to encrypt and decrypt with it.

SWIFT - Realm db encryption not working

Im trying to encrypt the data stored in the realm database. I followed the Sample Code mentioned on Realm's Swift page. I want to encrypt the data NOT the database file. Below is the code I'm using:
var error: NSError? = nil
let configuration = Realm.Configuration(encryptionKey: EncryptionManager().getKey())
if let realmE = Realm(configuration: configuration, error: &error) {
// Add an object
realmE.write {
realmE.add(objects, update: T.primaryKey() != nil)
}
}
Where objects is a list of objects i need to insert in the database. Below is the code fore getKey() func also picked from the sample code:
func getKey() -> NSData {
// Identifier for our keychain entry - should be unique for your application
let keychainIdentifier = "io.Realm.test"
let keychainIdentifierData = keychainIdentifier.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// First check in the keychain for an existing key
var query: [NSString: AnyObject] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData,
kSecAttrKeySizeInBits: 512,
kSecReturnData: true
]
// To avoid Swift optimization bug, should use withUnsafeMutablePointer() function to retrieve the keychain item
// See also: http://stackoverflow.com/questions/24145838/querying-ios-keychain-using-swift/27721328#27721328
var dataTypeRef: AnyObject?
var status = withUnsafeMutablePointer(&dataTypeRef) { SecItemCopyMatching(query, UnsafeMutablePointer($0)) }
if status == errSecSuccess {
return dataTypeRef as! NSData
}
// No pre-existing key from this application, so generate a new one
let keyData = NSMutableData(length: 64)!
let result = SecRandomCopyBytes(kSecRandomDefault, 64, UnsafeMutablePointer<UInt8>(keyData.mutableBytes))
// Store the key in the keychain
query = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: keychainIdentifierData,
kSecAttrKeySizeInBits: 512,
kSecValueData: keyData
]
status = SecItemAdd(query, nil)
assert(status == errSecSuccess, "Failed to insert the new key in the keychain")
return keyData
}
The problem is this that the code is not getting encrypted. After inserting data when i open the realm file using Realm Browser the code is NOT encrypted.
Tested on both simulator and device. Using Swift 1.2, Xcode 6.4, Realm 0.95.
Any ideas?
Realm's encryption feature applies only to the ability to encrypt whole .realm files. There's no feature to encrypt discrete objects within the .realm file and leave the rest as-is.
If you do want to go about doing this, I'm afraid you would need to roll the encryption system yourself.
If I was going to do this, I'd do it this way:
Create a Realm Object subclass with an NSData property called
encryptedData.
Serialize any objects you wanted to encrypt to NSData using the
NSCoding protocol. (Saving custom SWIFT class with NSCoding to UserDefaults)
Encrypt that resulting NSData object using an encryption method of your choice (AES Encryption for an NSString on the iPhone)
Take the resulting encrypted NSData object and save it to the encryptedData property in your Realm object.
Reverse the process when you want to retrieve that data.
While this process would work, as you can see, it's a non-trivial amount of extra work, and you would also lose all of the speed and memory-saving benefits of Realm in the process.
I would encourage you to rethink your app's design, and see if it is feasible to use Realm's own encryption feature after all. Good luck!

getting certificates from p12 file in IOS

I am stuck on this problem for many hours now and cannot find any solution. I have a p12 file which may contain some key pairs and also some certificates on their own. When I try the following code below, it gives me the list of only key pairs but not standalone certificates.
//open the p12 file
let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource(“keychainfile”, ofType: "p12")!
let pdata : NSData = NSData.dataWithContentsOfMappedFile(path)! as NSData
let dictionary = [String(kSecImportExportPassphrase!.takeRetainedValue()) : “password”]
var keyref: Unmanaged<CFArray>?
var error = SecPKCS12Import(pdata, dictionary, &keyref)
//retrieve file entries
var list = keyref!.takeRetainedValue() as NSArray
println(list.count) // finds only key pairs
And also part 2 of my question is that how can I retrieve only one specific certificate (by alias or name) from the p12 file instead of getting all of the entries and then looping through to find the certificate I am looking for?

Resources