iOS MDM profile signing, which certificate to use? - ios

Okay, so look at this diagram.
There are two little boxes, that signify how a given profile should be signed.
In Phase 2, step 1, it says "Apple issued certificate", but it doesn't say which apple issued certificate (they issue more than one). I have tried my developer certificate and the MDM (APNS) certificate. It wasn't one of those. Is there a third magic certificate I somehow need (and how do I get it)?
In Phase 3, step 2, it says "Identity certificate", but again it's a little sketchy on the details. The only identity certificate I know of is installed on the device, using the device's private key, how is the server supposed to use that to sign a profile?
The only way I've gotten this to work, is by creating my own self-signed certificate, and pre-installing it on the device. Obviously this is not an elegant or particularly secure way to do things.
Follow up questions
My server certificate is issued by "DigiCert High Assurance EV Root CA" and is on the list: http://support.apple.com/kb/ht5012, but iOS 6 devices consider it "untrusted" when signing profiles, but just fine for SSL which is wierd. iOS 5 devices are fine though. Any idea why?
I don't really understand the encryption bit either. From the MDM documentation: "Each device must have a unique client identity certificate. You may deliver these certificates as PKCS#12 containers, or via SCEP. Using SCEP is recommended because the protocol ensures that the private key for the identity exists only on the device."
While I agree it is ultimately more secure that only the device itself knows its private key, it's somewhat problematic as a 2048-bit public key can only be used to encrypt about 100 bytes of data, which isn't enough for even the smallest possible payload.

Let me go over phase 2 and phase 3 first
In the Phase 2, step 1, iOS device will send to a server response which is signed by device certificate/key (each device comes with preinstalled certificate/key which is different for each device). These on device certificates/keys are issued by Apple.
On the server side, you should verify it using Apple Root Cetificate.
In the Phase 2, step 1-3 your profile service will send a SCEP request. This SCEP request contains information to let device know to which SCEP server it should talk. This SCEP server is your server. So, a device will talk to this SCEP server and will request new identity certificate from it.
In Phase 3, step 2 device response will be signed with certificate/key of this identity certificate. And now you should verify it with your Certificate authority root certificate. (One more note SCEP server in Phase 2 is kind-of proxy to yours Certificate authority)
And now answering your questions "MDM profile signining, which certificate to use?"
MDM profile could be encrypted and/or signed.
If you want to encrypt it, you encrypt it using identity certificate associated with this device. So, device which has a key for this identity, so it can decrypt it.
If you want to sign it, you sign with your server key. Device should have a server certificate installed, so it can verify signature.
BTW. On this subject. One thing which isn't shown on this diagram, but usually is requited - first step (before whole this enrollment) is usually installation of server certificate (for future profile signature verification). Potentially, you can skip this step if your server certificate is issued by well known CA (as example Verisign or something like that).
Let me know, if you have any followup questions. It took me a while to understand whole this OTA/MDM enrollment.
Update 1
I don't know why iOS 6 treat your certificate as untrusted for signing. I didn't work with certificates which were signed by well known CA's.
I have only one guess. It could be that between iOS 5 and iOS 6 they changed something regarding key chain. Generally speaking, each app has it's own key chain. And all well known certificates, I believe should be stored in Mobile Safari keychain. It could be that MDM/Preferences shared this keychain with MobileSafari in iOS 6 and now they don't share it.
In such case, you will have to install this "DigiCert High Assurance EV Root CA" through a profile (to put it in correct keychain). However, it's wild guess.
Regarding encryption. First of all, you are right, if each device has it's own private key, it's way more secure. In such case, if anybody will steal a profile they won't be able to decrypt it (because only a device has a private key to do so). This is especially critically, if you are sending down profiles which are sensitive (as example, email account with both user name and password).
Very high level introduction into cryptography:
Any key (with any length) can encrypt data of any length. All encryption algorithms are designed that way that you can use the same key to encrypt any amount of data.
Asymmetric algorithms (like RSA) rarely used to encrypt data directly. In most cases, this algorithm is used to encrypt a key for symmetric algorithm (as example AES) and all following encryption/decryption is done using AES. There are two reasons for that: performance (AES is faster then RSA) and resources (AES is less resource hungry than RSA).
So, as result, if you need to encrypt profile you use PKCS7, which is internally uses RSA, AES (or other algorithms). Usually, you have a library to do this (OpenSSL or BouncyCastle). So, you don't have to figure out all these complexities.
BTW. If you have questions which aren't good fit for SO, you are welcome to contact me directly (my contact info in my profile).

Related

Certificate provisioning for IoT

I am considering to upscale an IoT project I'm running with esp32. I want to spend some time figuring out a correct way to provision certificates
I made an infrastructure in mind but don't know if it's secure enough.
I want to communicate between my MQTT server and a lot of devices. The thing I want to do now, is generating a self-signed certificate to use as a CA. Then generate for every device a private key with, sign it with the CA and store them in an encrypted NVS partition. When a certificate then nears the end of his life, I would make a new key and certificate and send them using the mutual secured MQTT chanel to replace the previous one. This way the server don't need to store private keys too.
For the CA, I just can't imagine what it would make less secure than a certificate that already is signed by a higher CA as long I'm using my own ecosystem.
Is this approach realistic and secure? Or can I better use something like AWS where everything has been done for me?

iOS - how do I get server certificate into iOS client keychain for pinning

TL;DR version: Is there any way to pass a Server certificate to an iOS client that doesn't involve also passing along the Server's private key?
I have written an iOS client app that communicates with my macOS server app (so I have control over both ends). I have implemented certificate pinning using a self-signed certificate to make things more secure. To accomplish this during development, I hardcoded the Server cert into the iOS client app and told the client to only connect to a server that gives you that exact cert during the TLS handshake. Everything is working great.
However in the real world I am selling this system as a set (1 Server, multiple clients to each customer), so I cannot hardcode a Server cert into the iOS client. My plan is to instead deliver the Server cert out of band (via email) to the iOS client like mentioned here: Making Certificates and Keys Available To Your App:
Apps can only access keychain items in their own keychain access groups.
To use digital identities in your own apps, you will need to write code to import them. This typically means reading in a PKCS#12-formatted blob and then importing the contents of the blob into the app's keychain using the function SecPKCS12Import
One way to provision an identity is via email. When you provision a device, send the associated user an email with their client identity attached as a PKCS#12 file.
My problem is that a .p12 file contains the certificate and the private key of the server - this seems very wrong to pass the private key along as well.
Is there any other way to pass the Server certificate to the iOS client that doesn't involve also passing along the Server's private key?
Thanks!!!
I was overthinking things here, the solution is actually pretty simple.
I just needed to email the Server's public certificate out of band to the client device with a custom extension like cert.myCustomExt1234. This is because the .crt extension is already claimed by iOS so you have to register your app to handle custom extensions (see apple docs here). Then in my app I can do all the logic of cert pinning using that out of band delivered Server public cert.
The key was changing the file extension to something not already claimed by iOS.

Would iOS AFNetwork SSL Pinning mode provide additional security bonus if valid certificate deployed

As per my understanding, SSL Pinning is to compare the public key or certification of a server with the copies bundled in the client beforehand.
I saw in Stackoverflow that many developers use SSL Pinning by AFNetwork libraries, but most of them use it along with a self-signed certificate.
I have bought a valid certificate from a CA and passed the test to verify it worked fine. I mean, I set the following and it worked
...
_sharedHttpsInstance.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
_sharedHttpsInstance.securityPolicy.allowInvalidCertificates = NO;
...
What I am wondering is that if set the Pinning mode to AFSSLPinningModePulicKey, my application would be more secure in communication with the server in addition to what the valid certificate have provided?
thanks a lot.
I'm don't know the exact implementation of SSL pinning in iOS, but in principle pinning provides definitely more security than the default verification against a set of builtin certificate agencies. By default systems trust more than 100 different CA from all over the world and each of the CA has the ability to issue any certificate it wants, even if another CA has already issued the same or a similar certificate. So if any of these 100+ CAs gets compromised they can issue a certificate for your domain, which would pass the checks in your application unless you use certificate pinning. Such compromises happened in 2011 with DigiNotar (no longer existent because of that) and Comodo (was too big to fail).
Probably the most prominent user of certificate pinning is Google Chrome, where it is used for the google domains and this helped to detect the compromises of DigiNotar and Comodo.
A downside of certificate pinning might be, that the application will stop working inside networks which do SSL interception for security reasons. Google Chrome seems to deal with this situation by accepting the certificate if it is signed by a CA explicitly added by the user (i.e. no builtin) alternatively to the pinning checks.
Another question which might be interesting is if SSL pinning is secure 'ENOUTH' for 'Most' of the application, even if working along with self-signed certification?
Checking against a fixed certificate or public key (e.g. certificate pinning with or without self-signed) is more secure than only checking if the certificate is signed by any of the 100s CAs trusted by the system. And as long as the developer has full control about both sides (e.g. application and server) it also scales well. The only advantage of additionally using the usual infrastructure is the use of the certificate revocation mechanism. But because the developer has control of the application (s)he could just replace the appplication in case the certificate gets compromised. So yes, in most cases it is secure enough do do SSL pinning with a self-signed certificate and it is more secure than using the standard certificate validation without pinning.
It's very difficult to say categorically whether pinning is better or worse, since it shifts the risk to a different party.
Pinning will essentially protect you better against a potential breach in any of the CA you trust. If a CA is compromised and made to issue a certificate for the host you're trying to contact, pinning will protect you against that because you will compare with the specific reference you've pinned, instead of going through the CA.
The downside is that it will prevent you from using the mechanisms in place at the CA to deal with a compromised host: certificate revocation. If the host's private key is compromised, going through the PKI verification mechanism should allow you to check for revocation, and be warned that such a problem happen. In contrast, you won't be able to know that with pinning, since you're not going through the CA to check the certificate at all.
Of course, you could combine both approaches, but this could cause additional problems (you'd need a strategy to deal with conflicting outcomes in both evaluations, otherwise a compromised CA revoking a valid cert could cause a DoS).
I don't know whethet AFNetworking's pinning mechanism replaces the PKI validation or complements it.
In general, choosing between using pinning or PKI validation depends on whether you think that particular host's private key is more or less likely to be compromised than the CAs you trust.
Another downside of pinning is that you need to update the application (or let the user "re-pin") every time the server certificate (or at least the key-pair, depending on what you've pinned) is changed legitimately. It's probably not a bad idea to re-key once in a while.
(To be clear, I'm not saying that CAs are better, just that pinning changes the set of problems.)

IOS PKIOperation signature certificate's generic CN in mdm enrollment scep step

I am developing mdm server and I have a problem with one of enrollment steps. The problem is scep step. I implement a scep server which handles Device CACert request and sends our server certificate in der format. After that, device sends encrypted and signed csr. But I can not verify signature of message. I think device creates a self-signed-certificate and sign message with it. We think that because signature certificate's common name is changing each "PKIOperation" request. But we must verify this signature because of security.
For example in each 3 enrollment request, certificate of csr signature changes. Their common names are:
CN=6E4F65AD-1E64-4E4D-A96E-2039EB140041
CN=2E33C2CC-14B8-47AC-938B-DCC7F8DA8715
CN=6817ED48-AB79-4FF0-A1A9-42C2AC303672
Note: The other steps of enrollment device sign messages with proper certificate and I can verify them. Only scep PKIOperation request is my problem. Is there any profile flag to set or something to solve this problem?
I may be wrong in some details, because I touched this about two years ago.
However, as I remember it's part of a protocol
If you take a look at SCEP draft: https://datatracker.ietf.org/doc/html/draft-nourse-scep-23#page-30 you will see this:
When building a pkiMessage, clients MUST have a certificate to sign
the PKCS#7 [RFC2315] signed-data (because PKCS#7 [RFC2315] requires
it). Clients MUST either use an existing certificate, or create a
self-signed certificate (see Section 2.3).
If the requester does not have an appropriate existing
certificate, then a locally generated self-signed certificate
MUST be used instead. The self-signed certificate MUST use the
same subject name as in the PKCS#10 request.
However, I was under impression that iOS device uses certificate/private keys which are built into the device. And this certificate is signed using Apple certs. And actually, as I remember they had exactly the format of CN, which you shown.
So, generally speaking it's ok if device uses self-signed certificate for first communication to the SCEP server (PKIOperation) and uses a certificate issued by your CA later on.

Recover signing certificate without p12 password?

I've been handed an iOS app codebase, which I'd like to distribute via the existing Enterprise certificate used by the prior developer.
After importing the provided .mobileprovision file, I'm (not unsurprisingly) getting the "Valid signing identity not found" error. Specifically when building:
The identity '[name]' doesn't match any valid, non-expired certificate/private key pair in your keychains
I was given the original CertificateSigningRequest.certSigningRequest file, a .p12 file, and the .cer file. I was not given the password to the .p12 file.
Is it possible to rebuild what I need from the CertificateSigningRequest.certSigningRequest without the .p12 file's password? I can likely get the .p12 password, but not in a timely manner.
Thanks!
I recognize that you've solved your issue by getting the password for the .p12 file, but I thought I'd shine a little light on what lives in each of those files you mentioned for the benefit of anyone running across the question in the future.
To answer the main question in this question: Can I rebuild what I need from the CertificateSigningRequest.certSigningRequest file?
Regrettably the answer is a very solid 'No'. The root cause of this is the very heart of Public Key Infrastructure (PKI), a set of management technologies, people, and practices dealing with the creation, verification, use, and revocation of digital certificates. Central to PKI is the notion of a public-private key pair. The 'Public' key is the one you share widely, anyone may have a copy of it and anyone wishing to validate messages signed by a digital certificate will require access to this key. The 'Private' key is the linked key that only you (or more accurately, your machine) knows and uses when signing messages. It is this signature that is verified via use of the 'Public' key that is shared widely authenticating that the message is in fact authentic.
When we are constructing development or distribution certificates, we are inherently asking Keychain Access, openssl, or your preferred SSL toolchain to create a public-private key pair. The public key goes into the CertificateSigningRequest file along with the other 'Subject' fields like name and email address and we ship this file off to Apple. That file primarily tells Apple what Public Key they can use to validate your app signature -- it does not give them a copy of your Private Key after all, if others had your private key they'd be able to codesign as you effectively destroying the notion of accountability on the iOS platform (ex. This App's signature checks out as valid, but I still don't know if it was actually signed by a developer I trust...). At no point in time, is your Private Key transmitted to Apple or the Developer Portal; it resides quite happily in your Keychain until such a time as 1) The certificate expires, 2) you actively revoke the certificate from the Developer Portal, or 3) you accidentally (or intentionally) delete the keypair from Keychain.
So what lives in each of these files?
CertificateSigningRequest.certSigningRequest - This contains a copy of the Public Key from the Public-Private keypair you generated locally, plus some additional required subject information required by the Certificate Signing Request format. Apple disregards this additional information and uses the name and email address they have on file for your Developer Account when constructing your certificate.
.p12 - This is a PKCS#12 formatted file containing a copy of the Apple-issued Certificate (which itself contains the Public Key) and a copy of the linked Private Key. This data is encrypted to prevent unauthenticated access and thus requires a password to decrypt.
.cer - This is the Apple-issued Certificate that contains the Public key portion of the key pair. This certificate is used by Apple to validate that Apps you submit are not tampered with while in transit to the App Store review team:
You sign your app using the Private key that only you know and upload the signed binary to Apple.
Apple then validate the signature using the public key that you've already shared with them.
If the math works out, then the App hasn't been tampered with and you are good to go.
If the math doesn't work out, either the app was tampered with, or (much more likely) the certificate was revoked or regenerated and the app was signed with an old or incorrect key pair.
As you can see, the only places the Private Key resides is in the original developer's keychain as well as the encrypted .p12 file. Consistent with both your comment and flup's comment, you either have to get the password to that .p12 file or look into breaking through the encryption.
Regardless, good to hear that you were able to get the password from the original developer. Let me know if you have any followup questions.

Resources