In iOS MCSession, you can initialize the section using the following method
initWithPeer:securityIdentity:encryptionPreference:
Most online tutorials the authors put nil for securityIdentity.
However, I wonder whether any damage (hacked) if leaving nil for the real app.
If so, how to generate a SecIdentityRef for this?
I found the following articles/discussions about Security in iOS, but still have trouble to connect SecIdentityRef with MCSession.
Thank you for precious time on my question, and any comment will be helpful.
Securing and Encrypting Data on iOS:
http://code.tutsplus.com/tutorials/securing-and-encrypting-data-on-ios--mobile-21263
How to establish a SecIdentityRef in an iPhone keychain ? (Without a .p12):
How to establish a SecIdentityRef in an iPhone keychain ? (Without a .p12)
Generate key pair on iphone and print to log as NSString:
Generate key pair on iphone and print to log as NSString
Related
I have a iOS application that I'm developing and the application must be bundled with a certificate in order to use the application since it makes use of webview and the site can not be accessed without the certificate.
I currently have a working solution but I noticed that when unzipping the .ipa file and looking into the code, I can see the password for the certificate very clearly as you can see from this line from the compiled code:
lastSampleTimeMainjsbundlecertificatep12PASSWORDHEREGCDAsyncSocketErrorDomain
A short code snippet of how I am retrieving the certificate:
[[NSBundle mainBundle] pathForResource:#"certificate" ofType:#"p12"];
NSData *p12Data = [[NSData alloc] initWithContentsOfFile:p12Path];
CFStringRef password = CFSTR("somePassword");
Is there any safe way to handle this type of scenario? Or will the password always be retrievable if it falls into the hands of someone who knows what he's doing.
Use the Keychain API.
https://developer.apple.com/documentation/security/keychain_services
That's the standard way to protect API_KEYS, Certs., Even Username and Passwords.
It's simple and compatible with Objective-C
EDIT: For Certificates: https://developer.apple.com/documentation/security/certificate_key_and_trust_services/certificates/storing_a_certificate_in_the_keychain
A simple solution might be to just obfuscate the string, creating the password string from a byte-array, but that's still not very safe.
Some explanation here.. also to consider, loading the password to a string should be avoided, as it could be read from the heap at runtime:
https://stackoverflow.com/a/8881376/20283130
This happens on iOS 13.3 (iPhone 11)
I developed a react native iOS app which saves/loads data into/from keychain via https://github.com/mCodex/react-native-sensitive-info/blob/master/ios/RNSensitiveInfo/RNSensitiveInfo.m
My read/write keychain options is below, it never changes and works well since day1
const defaultOptions: RNSensitiveInfoOptions = {
touchID: true,
kSecAccessControl: 'kSecAccessControlBiometryAny',
kSecUseOperationPrompt: 'We will store data securely on your device.',
sharedPreferencesName: 'sensitive',
keychainService: 'sensitive',
};
Recently one of my clients complain about the data cannot be retrieved from keychain because of errSecNotAvailable = -25291, /* No keychain is available. You may need to restart your computer. */
I thought there might be something wrong happened to keychain, so I tried set a single key/value item with the same option (so the kSecAttrService and kSecClass are same with business related items): 'foo' -> 'bar'. And I can load this value out via the same option.
I did more experiences:
if I read a key doesn't exist, the keychain API will return error errSecItemNotFound -25300
if I read a business related key, the keychain API return error errSecNotAvailable -25291
I jailbreak this iPhone and use https://github.com/ptoomey3/Keychain-Dumper to dump the items but it prompt (although the phone is unlock):
[INFO] No Generic Password Keychain items found.
[HINT] You should unlock your device!
I copied Keychain-2.db from device to local computer and using sqlite DB to query the generic password items, looks like they are there (but as they are encrypted, i am not sure 100%):
I am expecting someone could suggest:
why this issue could happen?
is there any possibility I can restore the keychain data?
I inherited a Xcode setup that builds an iOS app that uses Automatic Signing for the development builds. I now have the task to build some CI setup for this project, but without changing the actual Xcode project. This means I can't switch to manual signing for now.
As the project is building fine locally, I didn't expect this to be a big problem, but it turns out Automatic Signing (obviously, in hindsight) needs your Xcode to be signed into the Apple ID (Xcode => Preferences => Accounts) that should be used for automatically creating certificates.
Is there a way to add an Apple ID to Xcode via the command line?
This is what I already did:
I looked around already, but could not find any obvious answers via Google. All the questions and answers here on StackOverflow always mention "Just quickly open Xcode and enter your credentials" which unfortunately does not work on our CI setup.
I found this Jenkins "Xcode Plugin" that lets you import a .developerprofile that you can export from Xcode. But my Java is really rusty and I couldn't fully understand if this "only" imports profiles and identities, or also the list of accounts.
Playing around with an .developerprofile myself, it seems to include the account information (and all the certificates etc.) in a .zip file, so you can extract the files. That also includes a accounts.keychain and accounts.plist, but those are both encrypted with the password - which I don't know how to use to get to the real data to investigate there further.
I also tried to find out where Xcode originally saves the information if you add a new Apple ID: It seems to put the account names and passwords, and some token, into your "login" (com.apple.gs.xcode.auth.com.apple.account.AppleIDAuthentication.token) and "iCloud" keychain (Xcode-AlternateDSID and Xcode-Token). I also couldn't recreate the existing entries in Keychain access manually, as "Access Control" -> "Access group for this item:" was always different when creating an application password manually. Copying the items into a new keychain to be exported also didn't work, as the iCloud keychain doesn't let me copy stuff over to a new one (even after disabling keychain sync in iCloud, so the keychain is named "local items").
First off, I'm not sure that what you are trying to do is a good idea.
Keep in mind that if you are going to set up Xcode to automatically request iOS developer certificates on every build, and that build executes on different machines (say, hosted CI such as Travis or Azure Pipelines), your iOS developer certificate will be revoked and regenerated every time.
A much better option (in my opinion) is to export your iOS development certificates and provisioning profiles via your developer profile, and import the development certificate and provisioning profile in your build environment. Then, if needed, update your Xcode project to use the certificate and profile you've just imported.
I think Fastlane can already do pretty much all that. If you're looking for inspiration, Azure Pipelines has similar functionality. The have a task which installs a provisioning profile, one which installs a certificate and one which builds an Xcode project and allows you to override the certificate and provisioning profiles used when signing your product.
Having said that, the accounts.plist and the accounts.keychain probably contain the information you are looking for. Both files are encrypted using AES encryption.
The key used to encrypt the file is derived from the password using PBKDF2 (Password-Based Key Derivation Function 2), using these parameters:
Hashing function: SHA256
Password: Your password
Salt: The byte representation of your password, using UTF8-encoding
Number of hashing iterations: 33333
Key length: 10
The 'magic numbers' are the default values used by Apple's SecKeyDeriveFromPassword function, as described here and implemented here
Once you have your encryption key, you can decrypt the file. You'll need an initialization vector (IV), which again is the default value used by Apple - a 16-byte array consisting entirely of zeros.
In C, you should be able to use use code like this to generate the encryption key:
CFStringRef password = CFSTR("verysecretstuff");
const char* saltBytes = CFStringGetCStringPtr(password, kCFStringEncodingUTF8);
CFDataRef salt = CFDataCreate(NULL, saltBytes, CFStringGetLength(password));
int keySizeInBits = kSecAES128;
CFNumberRef keySize = CFNumberCreate(NULL, kCFNumberIntType, &keySizeInBits);
int rounds = 33333;
CFNumberRef numberOfRounds = CFNumberCreate(NULL, kCFNumberIntType, &rounds);
CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(NULL, 3, NULL, NULL);
CFDictionaryAddValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES);
CFDictionaryAddValue(parameters, kSecAttrKeySizeInBits, keySize);
CFDictionaryAddValue(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256);
CFDictionaryAddValue(parameters, kSecAttrRounds, numberOfRounds);
CFDictionaryAddValue(parameters, kSecAttrSalt, salt);
CFErrorRef error = NULL;
SecKeyRef key = SecKeyDeriveFromPassword(password, parameters, &error);
To decrypt the data, use:
const UInt *bytes = NULL; // Encrypted data
CFDataRef data = CFDataCreate(NULL, bytes, length);
CFErrorRef error = NULL;
SecTransformRef transform = SecDecryptTransformCreate(key, &error);
if ( transform == NULL )
{
CFShow(error);
CFRelease(error);
}
SecTransformSetAttribute(transform, kSecEncryptionMode, kSecModeCBCKey, &error);
SecTransformSetAttribute(transform, kSecPaddingKey, kSecPaddingPKCS7Key, &error);
SecTransformSetAttribute(transform, kSecTransformInputAttributeName, data, &error);
CFDataRef result = SecTransformExecute(transform, &error);
CFShow(result);
CFRelease(result);
CFRelease(data);
CFRelease(transform);
Hope it helps!
Currently i have an application which has a "Remember Me" option for storing User ID.So to store this currently i am using Keychain APIs.
But i have a doubt if by chance device is stolen and somebody jailbreak the device. Can he able to get all these data from keychain?
How to prevent this ?
The most important thing when using the KeyChain is to not use kSecAttrAccessibleAlways or kSecAttrAccessibleAlwaysThisDeviceOnly because then data is not encrypted securely (see Apple's documentation). Not using these adds a layer of security to KeyChain data, but still, a strong passcode would be required by the user to protect his data. If the user has no passcode on the device, the data is unprotected. If the user has a 4-digit passcode (the standard), the data is protected very weakly and can be brute forced in minutes.
If you require protection from jailbreak (and other attacks), your best option is to not use the KeyChain, but create an encrypted sensitive data store of your own and require the user to have a secure passcode. Store the data encrypted using a key generated from that passcode.
This could inconvenience your users, so if you wish to provide a grace period between requiring passcode, think of a way to provide a session cookie to the app which is invalidated after a set period of time.
To be extra safe I'd add another layer of security on top of everything and make a simple check if the device is jailbroken. If that's the case I'd delete the current KeyChain \ sensitive data.
Something like that:
NSString *filePath = #"/Applications/Cydia.app";
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
//Device is jailbroken --> delete KeyChain
}
Or even better:
FILE *f = fopen("/bin/bash", "r");
BOOL isbash = NO;
if (f != NULL)
{
//Device is jailbroken --> delete KeyChain
isbash = YES;
}
fclose(f);
Here is the best way for checking if Device jailbroken
Code that checks
bool forked = fork();
if (forked) {
// Device is jailbroken
}
Check this link Keychain Items, where you can enumerate all keychain items.
You can also use Protection Attributes for securing info.
Apple Docs
Good Read
Note this question is was asked in 2001. Things have changed.
I have an iOS device that needs to access a Junos VPN. The opaque instructions from the Junos admin say that I have to retrieve a certificate that has been provisioned to the device using the Apple IPCU. I know that the cert is on the device (I can see it in Settings) and I can access the VPN though Mail, Safari and the Junos App.
The Apple docs state that each app has its own keychain and yet all three of these apps can see the cert. The fact that Jusos can access a cert provisioned by IPCU implies that any app can access this certificate. However when I try to locate it:
CFTypeRef certificateRef = NULL; // will hold a ref to the cert we're trying to retrieve
const char *certLabelString = "myCertificateName"; // c string of the certificate we're searching for.
CFStringRef certLabel = CFStringCreateWithCString( NULL, certLabelString, kCFStringEncodingUTF8); // the search we need - a string match for a UTF8 String.
const void *keys[] = { kSecClass, kSecAttrLabel, kSecReturnRef };
const void *values[] = { kSecClassCertificate, certLabel, kCFBooleanTrue };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, 3, NULL, NULL); // set up a search to retrieve this certificate.
OSStatus status = SecItemCopyMatching(dict, &certificateRef); // Search the keychain, returning in dict
if(status != errSecSuccess)
NSLog(#"keychain find returned %ld", status);
if(dict)
CFRelease(dict);
It fails. My questions:
Is this code correct? Actually I know
it isn't because
SecItemCopyMatching returns
errSecItemNotFound
What value should I use for
certLabelString - I am assuming the
human readable name shown in
Settings.
In Settings, the cert looks like this (sadly obfuscated to death) the search text I specify is exactly the text shown in settings.
Cross posted to Apple developer forums
So the answer (on the Apple forums) is that mail.app and Safari.app share the Apple keychain identifier and this is the only keychain that you can push certificates to using the Apple MDM tool. Anyone else who comes up against this should file a defect in order to encourage Apple to do the right thing.
Since middle of 2015, there is now the Safari Services framework (next to WKWebView and UIWebView, we now have a SFSafariViewController). SFSafariViewController has the ability to access the apple keychain and therefore can use all identities :) Very nice.
https://developer.apple.com/videos/play/wwdc2015/504/
https://developer.apple.com/library/ios/documentation/SafariServices/Reference/SafariServicesFramework_Ref/index.html#//apple_ref/doc/uid/TP40016218