I'm trying to figure out what exactly means the status code errSecDuplicateItem for the SecItemAdd method when trying to add a certificate identity to the iOS keychain.
Reading the iOS documentation, it only says that this status code means the item is duplicated in the keychain, but what is the criteria to determine if an identity is a duplicate? Issuer name? Expiration date? Both?
If you read to the Mac OSX documentation, the discussion section for a similar method says the following:
If the certificate has already been added to the specified keychain,
the function returns errSecDuplicateItem and does not add another copy
to the keychain. The function looks at the certificate data, not at
the certificate object, to determine whether the certificate is a
duplicate. It considers two certificates to be duplicates if they have
the same primary key attributes.
I know there is a difference, I'm trying to save the certificate identity in the keychain, and this discussion is for the SecCertificateAddToKeychain method which saves the certificate; but I believe there is a connection.
What's the meaning of "primary keys attributes"?
I tried adding the same identity twice and of course I get the errSecDuplicateItem, but I'm afraid that users may get an error if they want to update the certificate in someway I'm not considering.
Any thoughts?
Thanks in advance
As far as I know, the keychain's primary key attributes aren't documented. However, according to a message from Ken McLeod, certificates are identified by their certificate type, issuer, and serial number. The keychain will refuse to accept more than one certificate that has the exact same values for these attributes.
Certificate authorities are required not to issue two certificates with the same serial number, so this error is unlikely to happen for your users. If you're generating certificates yourself, you must also make sure you do not accidentally reuse serials.
Related
In iOS, if pinned SSL certificate expires, do I need to re-submit the app? Will the apps with old version continue to work or will not work unless they are updated?
That entirely depends on how you pinned the certificate. Pinning a certificate means checking the certificate and its chain against a set of designated requirements that determine whether the new certificate should be accepted. There are nearly an infinite number of ways to do this, and thus nearly an infinite number of ways to shoot yourself in the foot while doing so.
As a rule:
If you are checking to see if the certificate's public key matches, you're fine as long as the new cert has the same public key. This is normally the simplest approach to get right, because you have the power to guarantee that a key under your direct control does not change. However, be aware that some automated certificate updating tools generate new keys by default.
If you are comparing the entire certificate, it will likely break, because obviously some aspects of the certificate (minimally, the expiration date) will change.
If you are comparing specific aspects of the certificate, such as the public key of the CA cert that signed it, it may or may not break, depending on whether those designated requirements match.
Be aware, however, that CAs periodically rotate out their signing keys to limit damage in the event of a key getting compromised. What this means is that the specific CA cert key that you pinned may not be the one that gets used to sign a subsequent certificate. And if you are doing this in an automated fashion, it isn't a question of whether you will break, but when.
For this reason, if you feel the need to do key pinning, it is strongly recommended that you pin only keys that are under your direct control, and that you force any automated update tools to reuse the existing key pair.
No. once you install ssl on your site or renew old one, it will start working. no need to resubmit the app.
read more at SSL Pinning and certificate expiry
I have few questions regarding Identity certificate in Profile Payload.
Forgive the ignorance, if some questions are basic.
1.) I found that, we can either use SCEP standard or PKCS12 certificate directly for device identification. SCEP is recommended, since private key will be known only to the device. So in case If I am going to implement SCEP server, do I need to maintain the list of Public key of Identity certificates mapped to the device, so that I can use it later for encrypting?
2.) What is the best possible way to implement SCEP server.? Is there any reliable robust methods available to adopt it instead of writing everything on our own?
3.) What if the identity certificate is expired?
As a basic version while playing around, I tried to add my own p12 certificate to the Payload without using SCEP.
I tried to add the base64 encoded p12 certificate in the identity payloadcontent key,as mentioned in some link reference. I got an error
The identity certificate for “Test MDM Profile” could not be found
while installing profile.
identity_payload['PayloadType'] = 'com.apple.security.pkcs12'
identity_payload['PayloadUUID'] = "RANDOM-UUID-STRING"
identity_payload['PayloadVersion'] = 1
identity_payload['PayloadContent'] = Base64.encode64(File.read "identity.p12")
identity_payload['Password'] = 'p12Secret'
When I checked 'Configuration Profile key reference', it was mentioned that I should send Binary representation of Payload in Data.
So I tried,
identity_payload['PayloadContent'] = ConvertToBinary(File.read "identity.p12")
I got,
The password for the certificate “IdentityCertificate” is incorrect
I am supplying valid password for exporting the p12 certificate.
What am I doing wrong?
Answering your question:
1) Do I need to maintain the list of Public key of Identity certificates mapped to the device, so that I can use it later for encrypting?
Yes. You need some kind of mapping. You can do couple of ways:
Just store it in DB a mapping between certificate common name and device UDID.
Make CN contain UDID (I like this method, because it simplifies initial checks)
And as you pointed out you will need public key to encrypt payloads for this device.
2) What is the best possible way to implement SCEP server.? Is there any reliable robust methods available to adopt it instead of writing everything on our own?
There are open source implementation of SCEP. As example jSCEP have it (I used it) and EJBCA have it (I used it too). I saw other implementation (in Ruby and so on). So, you can find an choose something which works with your stack.
3) You need to renew identity certificate before it expeires (the same way as for any other certificates).
4) If your profile doesn't work, I would recommend you to create the same profile in iPhone Configuration Utility and compare with yours. Most of the time, you missed just one tag or something like that (it will take a lot to figure it out without comparing it with working one).
In an attempt to build an iOS project (in XCode), I need to import my colleague's public and private keys for the code signing identity, but I am unable to do so because I get an error in Keychain Access that says "An error has occurred. Unable to import an item. / The contents of this item cannot be retrieved"
FULL DETAILS:
I have got two keys from my colleague's computer, exported them from his Keychain as two files:
Roomer Inc.p12 (the private key)
Roomer Inc.pem (the public key)
When he exported these, he left the password blank (Although we also tried with a password of "test" and got the same results).
When I double-click Roomer Inc.p12 (for the private key), it opens in Keychain Access and promts me to choose the keychain ("login" is selected by default)
I click "Add" and then I am prompted for the password to the keychain (which I leave blank)
Next I always see this message in Keychain access:
However, despite this message appearing, when I click OK, I see a new private key entry for "Roomer Inc". Note that this entry is a private key in the "login" key chain as I would expect, but has no expiration date (should it?)
Next, for the Roomer Inc.pem file (the public key) I am asked to choose the keychain ("login") and I click Add
Then, I also get the "An error has occurred. Unable to import an item. / The contents of this item cannot be retrieved" message for the public key as well. In this case however (unlike the Private key), I do not see any entry corresponding for what I just added.
So, it appears that the private key entry may or may not be OK (I have no way to verify), and the public key entry for Roomer cannot be installed in the keychain without this error message. Please note that I also tried using the security import command to import the public key :
$ security import Roomer\ Inc.pem -f pkcs12 ~/Library/Keychains/login.keychain
1 key imported.
When I do this, although the command returns "1 key imported" I do not see a public key for "Roomer Inc" in my Keychain Access window (I closed out Keychain Access and re-opened it).
Either way, we have identified that this is our blocker. (The symptom of course is that the XCode project won't build for the AdHoc provisioning profile to be used with TestFlight). I have left off the additional steps regarding the XCode build and TestFlight setup, because we believe the core problem has to do with importing the keys as explained above.
We figured out our problem, and I am posting my answer here so that others may find it helpful.
The problem is really a UX problem with Keychain Access. Let me back up and give a little context: when you create a distribution certificate with Apple, you create it based on a PRIVATE KEY and App-based permissions.
In Keychain Access, the distribution certificate is listed as a child below the name of the private key that it was created from. Here's the catch: When you use the search box in Keychain access (in my case we were typing in "Roomer" because that's the name on our distribution certificate), it won't look for a certificate with that name, it will look for a certificate attached to a private key for that name.
So my colleague had create a distribution certificate based on a private key that was named "Jorge Davila" (his name), even though the distribution certificate was named "iPhone Distribution: Roomer Inc."
When he searched for "Roomer" in Keychain Access, the correct one was NOT displayed in the search results because the key this certificate was created from was named "Jorge Davila" not "Roomer". Thus, he was exporting the wrong certificate and didn't realize because there were others (some expired) with that name.
Here's how the correct one looks:
This is a relatively nuanced problem with the UX of Keychain Access and the fact that the search tool doesn't give you the results you expect it to. I am posting this answer in the hope that others may find it useful.
For one of my iOS apps I need to check two things:
Is there an active device lock (pass code)
Has the device lock been triggered by the correct authority / certificate (e.g. my own certificate). This is required to assure specific security guidelines.
For the first part of my question I found this answer - which is sufficient for me. How would you accomplish the second part?
Answering my own question.
First of all the correct question is not about validation of a certificate. It's about validation of meta information placed within a configuration profile (which in my case provides security guidelines for the device lock).
You have to create a custom CA and issue one certificate. The issued certificate has to be placed within your app, the custom CA's certificate goes into the configuration profile.
If the configuration profile is installed it is possible to check whether the certificate within the app binary was signed with the root certificate placed in the configuration profile.
It's not the most secure solution, but definitely a way to go.
--
This post put me into the right direction (Apple Developer Account required).
I am implementing SSL client authentication for our iPhone app and am using the app keychain to store the client identity (certificate + private key). After adding the items to the keychain, I am getting some unexpected results when using SecItemCopyMatching. Quick summary: I add exactly one SecIdentityRef to the keychain, but SecItemCopyMatching finds two afterwards. Let me start with the facts.
I am running my app on an iPod with iOS 4.3.5.
I have an empty app keychain to start with.
My certificates are all created using openssl and deployed to the iPod via a PKCS#12 file as an email attachment.
The PKCS#12 file contains:
Client certificate
Client CA certificate (issuer of the Client certificate)
Root CA certificate (issuer of the Client CA certificate)
RSA private key of the client certificate
SecPKCS12Import successfully imports the file and the resulting dictionary has the following content:
one "identity"
one "trust"
one "chain" (CFArray which holds the three certificates mentioned above)
Using SecItemAdd, I successfully add the "identity" to the keychain.
Next, I retrieve the "chain" array from the dictionary and attempt to add the certificates. In doing so, the first one fails with error errSecDuplicateItem. I assume this is because the first certificate is the client certificate and that it was already added to the keychain when I added the identity. The other two certificates are added without error.
Now, if I go back and use SecItemCopyMatching with these key/value pairs...
keys = {kSecClass, kSecReturnRef, kSecMatchLimit}
values = {kSecClassIdentity, kCFBooleanTrue, kSecMatchLimitAll}
...two identities are returned! Furthermore, if I retrieve the certificate for each (SecIdentityCopyCertificate) and then the summary (SecCertificateCopySubjectSummary), I see the both identities have the same certificate!
Lastly, when I try to clear the identities from the keychain (SecItemDelete), the first attempt is successful but the second fails with errSecItemNotFound.
It is clear from all the googling I have been doing that there are "issues" with the iOS keychain. However, I have not seen this reported; nor have I seen anything even remotely related.
So, my questions:
Am I using SecItemCopyMatching correctly?
When using SecItemCopyMatching to find identities in the keychain, how does it determine the identities that are present? Is this dynamic, or strictly based on how many SecIdentityRef items were added?
could this problem possibly be related to the certificates themselves? Note that despite this issue, I am still able to retrieve the first identity and certificates in order to respond to didReceiveAuthenticationChallenge.
I can post code and/or certificate dump, if needed.
Thanks in advance,
Ken Cross
Siemens Enterprise Networks.
As far as I can tell, you're using SecItemCopyMatching correctly.
SecIdentityRef items are not actually stored on the keychain; they are generated dynamically for certificates that have an associated private key available. Duplicate identities are indeed strange, and probably indicate a framework issue -- perhaps the framework gets confused by the duplicate in the second set of certificates? (Please do file a bug at bugreport.apple.com!) Does the duplicate identity go away when you restart the app?
On the other hand, duplicate identities won't necessarily lead to any actual problem. If you are worried that you might be using the wrong identity, simply ask SecItemAdd to provide a persistent reference to the one it "creates" and use that to retrieve the SecIdentityRef when needed.