我們的組織爲多個客戶端管理穩定的iOS應用程序,這意味着要處理大量不同的開發人員身份證書和推送通知證書。獲取Apple Keychain以識別Bouncy Castle .NET創建的PKCS12(.p12)商店
我已經成功推出了Bouncy Castle C# Crypto API簡化了推送通知的證書和私鑰管理,essentially eliminating the need for the Keychain for all our push notification certificates。
我想將其擴展到開發人員身份證書。目標是將每個開發人員身份的所有私鑰和證書信息存儲在數據庫中。然後,當需要配置新的開發人員或構建計算機時,服務器端代碼可以將所有證書和私鑰包裝到一個p12存檔中,並使用一個可導入目標Mac Keychain的密碼。
不幸的是,Mac的鑰匙串不喜歡我生成的p12文件。這很煩人,因爲我可以成功地將這些文件導入到Windows證書管理器中。
我使用(重要部件)的代碼如下所示:
private byte[] GetP12Bytes(List<DevIdentity> 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;
}
}
就像我說的,這在Windows進口的偉大工程,但無法與導入到Mac系統時一個非常通用的錯誤鑰匙扣。
有一個重要區別裝載鑰匙扣產生的P12和我自己生成的P12文件時,我所看到的,但我不知道這是原因。
如果我將Mac Keychain生成的p12加載到Bouncy Castle PKCS12Store中,然後檢查Keychain p12上的密鑰,那麼證書和私鑰都具有一個屬性,其中鍵爲「1.2.840.113549.1.9.21 「與等價值(一個值爲#af8a1d6891efeb32756c12b7bdd96b5ec673e11e的DerOctetString)。
如果我做同樣的我產生P12文件,私鑰包含「1.2.840.113549.1.9.21」屬性,但該證書不。
如果我Google "1.2.840.113549.1.9.21",我find out that this OID means PKCS_12_LOCAL_KEY_ID。我唯一的理論是鑰匙串依靠這個來匹配證書和私鑰,而且我生成的文件沒有這個,所以它失敗了。
不過,我試着將這些值到一個Hashtable,然後使用CertificateEntry構造函數的屬性哈希表。如果我這樣做,然後保存字節,然後重新加載字節,該屬性再次丟失。
所以我很失望。也許這個屬性是Bouncy Castle API中的一個小故障?也許有什麼我做錯了。也許鑰匙串對傳入的p12文件有非常荒謬的非標準要求。無論如何,任何可能提供的幫助將不勝感激。
嗨大衛,你有解決這個問題? – 2011-12-20 08:49:59