Our organization manages stable iOS applications for several clients, which means working with a large number of different developer identity certificates and issuing notification certificates.
I have had success with the Bouncy Castle C # Crypto API in simplifying the management of certificates and private keys for push notifications , essentially eliminating the need for Keychain for all of our push notification certificates .
I would like to extend this to developer ID certificates. The goal would be to store all the private key and certificate data in a database for each developer identifier. Then, when you need to prepare a new developer or build machine, server-side code can wrap all the certificates and private keys in one p12 archive with one password that can be imported into the target Mac keychain.
Unfortunately, Mac Keychain does not like the p12 files that I generate. This is annoying since I can successfully import these files in Windows Certificate Manager.
The code I use (important parts) is as follows:
private byte[] GetP12Bytes(List<DevIdentity> identities, string password)
{
Pkcs12Store store = new Pkcs12Store();
foreach(DevIdentity ident in identities)
{
var dotNetCert = new X509Certificate2(ident.CertificateBytes);
string friendlyName = GetFriendlyName(dotNetCert.Subject);
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);
Org.BouncyCastle.X509.X509Certificate cert = DotNetUtilities.FromX509Certificate(dotNetCert);
X509CertificateEntry certEntry = new X509CertificateEntry(cert);
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;
}
}
As I said, this works great for importing to Windows, but with a very common error when importing to Mac, Keychain does not work.
, Keychain p12 p12, , .
Mac Keychain, p12 Bouncy Castle PKCS12Store, , Keychain p12, , "1.2.840.113549.1.9.21", (DerOctetString # af8a1d6891efeb32756c12b7bdd96b5ec673e11e).
p12, "1.2.840.113549.1.9.21", .
Google "1.2.840.113549.1.9.21" , , OID PKCS_12_LOCAL_KEY_ID. , Keychain , , , .
Hashtable, CertificateEntry, hashtable. , , , .
, . , API Bouncy Castle? , - . , Keychain p12. , , , .