Note that there are some explanatory texts on larger screens.

plurals
  1. POGet Apple Keychain to recognize Bouncy Castle .NET created PKCS12 (.p12) store
    primarykey
    data
    text
    <p>Our organization manages a stable of iOS applications for multiple clients, which means dealing with a lot of different developer identity certificates and push notification certificates.</p> <p>I have had success with the <a href="http://www.bouncycastle.org/csharp/" rel="nofollow">Bouncy Castle C# Crypto API</a> in simplifying management of the certificates and private keys for push notifications, <a href="http://www.make-awesome.com/2010/12/apple-push-notification-certificates-without-the-mac-keychain/" rel="nofollow">essentially eliminating the need for the Keychain for all our push notification certificates</a>.</p> <p>I would like to extend this to the developer identity certificates. The goal would be to store all the private key and certificate information in the database for each developer identity. Then when a new developer or build machine needs to be provisioned, server side code could wrap all of the certificates and private keys into one p12 archive with one password that could be imported into the target Mac's Keychain.</p> <p>Unfortunately, the Mac Keychain doesn't like the p12 files I'm generating. This is annoying since I can successfully import these files into the Windows certificate manager just fine.</p> <p>The code I'm using (the important parts) looks like this:</p> <pre><code>private byte[] GetP12Bytes(List&lt;DevIdentity&gt; identities, string password) { Pkcs12Store store = new Pkcs12Store(); foreach(DevIdentity ident in identities) { // Easiest to create a Bouncy Castle cert by converting from .NET var dotNetCert = new X509Certificate2(ident.CertificateBytes); // This method (not shown) parses the CN= attribute out of the cert's distinguished name string friendlyName = GetFriendlyName(dotNetCert.Subject); // Now reconstitute the private key from saved value strings BigInteger modulus = new BigInteger(ident.PrivateKey.Modulus); BigInteger publicExponent = new BigInteger(ident.PrivateKey.PublicExponent); BigInteger privateExponent = new BigInteger(ident.PrivateKey.Exponent); BigInteger p = new BigInteger(ident.PrivateKey.P); BigInteger q = new BigInteger(ident.PrivateKey.Q); BigInteger dP = new BigInteger(ident.PrivateKey.DP); BigInteger dQ = new BigInteger(ident.PrivateKey.DQ); BigInteger qInv = new BigInteger(ident.PrivateKey.QInv); RsaKeyParameters kp = new RsaPrivateCrtKeyParameters(modulus, publicExponent, privateExponent, p, q, dP, dQ, qInv); AsymmetricKeyEntry privateKey = new AsymmetricKeyEntry(kp); // Now let's convert to a Bouncy Castle cert and wrap it for packaging Org.BouncyCastle.X509.X509Certificate cert = DotNetUtilities.FromX509Certificate(dotNetCert); X509CertificateEntry certEntry = new X509CertificateEntry(cert); // Set the private key and certificate into the store store.SetCertificateEntry(friendlyName, certEntry); store.SetKeyEntry(ident.PrivateKeyName, privateKey, new X509CertificateEntry[] { certEntry }); } using (MemoryStream ms = new MemoryStream()) { store.Save(ms, password.ToCharArray(), new SecureRandom()); ms.Flush(); byte[] p12Bytes = ms.ToArray(); return p12Bytes; } } </code></pre> <p>Like I said, this works great for import on Windows, but fails with a very generic error when importing into the Mac Keychain.</p> <p>There is one major difference I can see when loading a Keychain-generated p12 and my own generated p12 file, but I do not know if this is the cause.</p> <p>If I load the Mac Keychain generated p12 into a Bouncy Castle PKCS12Store, and then examine the keys, on the Keychain p12, both the certificate and the private key have an attribute with the key "1.2.840.113549.1.9.21" with equivalent values (a DerOctetString with value #af8a1d6891efeb32756c12b7bdd96b5ec673e11e).</p> <p>If I do the same to my generated p12 file, the private key contains the "1.2.840.113549.1.9.21" attribute, but the Certificate does not.</p> <p>If I <a href="http://www.google.com/search?q=1.2.840.113549.1.9.21" rel="nofollow">Google "1.2.840.113549.1.9.21"</a>, I <a href="http://www.antillia.com/sol9.2.0/classes/OIDNames.html" rel="nofollow">find out that this OID means PKCS_12_LOCAL_KEY_ID</a> . My only theory is that the Keychain relies on this to match up the certificate and private key, and that my generated file does not have this, so it fails.</p> <p>However, I've tried adding these values to a Hashtable and then using the CertificateEntry constructor that takes the attribute hashtable. If I do that, and then save the bytes, and then reload the bytes, that attribute is again missing.</p> <p>So I'm flummoxed. Maybe this attribute is a glitch in the Bouncy Castle API? Maybe there's something I'm doing wrong. Maybe the Keychain has ridiculous non-standard requirements for incoming p12 files. In any case, any help that could be provided would be greatly appreciated.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload