2 // PKCS12.cs: PKCS 12 - Personal Information Exchange Syntax
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // (C) 2004 Novell (http://www.novell.com)
10 // Key derivation translated from Bouncy Castle JCE (http://www.bouncycastle.org/)
11 // See bouncycastle.txt for license.
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
38 using System.Security.Cryptography;
42 using Mono.Security.Cryptography;
44 namespace Mono.Security.X509 {
53 public const string pbeWithMD2AndDESCBC = "1.2.840.113549.1.5.1";
54 public const string pbeWithMD5AndDESCBC = "1.2.840.113549.1.5.3";
55 public const string pbeWithMD2AndRC2CBC = "1.2.840.113549.1.5.4";
56 public const string pbeWithMD5AndRC2CBC = "1.2.840.113549.1.5.6";
57 public const string pbeWithSHA1AndDESCBC = "1.2.840.113549.1.5.10";
58 public const string pbeWithSHA1AndRC2CBC = "1.2.840.113549.1.5.11";
70 public const string friendlyName = "1.2.840.113549.1.9.20";
71 public const string localKeyId = "1.2.840.113549.1.9.21";
77 internal class SafeBag {
78 private string _bagOID;
81 public SafeBag(string bagOID, ASN1 asn1) {
86 public string BagOID {
87 get { return _bagOID; }
101 class PKCS12 : ICloneable {
103 public const string pbeWithSHAAnd128BitRC4 = "1.2.840.113549.1.12.1.1";
104 public const string pbeWithSHAAnd40BitRC4 = "1.2.840.113549.1.12.1.2";
105 public const string pbeWithSHAAnd3KeyTripleDESCBC = "1.2.840.113549.1.12.1.3";
106 public const string pbeWithSHAAnd2KeyTripleDESCBC = "1.2.840.113549.1.12.1.4";
107 public const string pbeWithSHAAnd128BitRC2CBC = "1.2.840.113549.1.12.1.5";
108 public const string pbeWithSHAAnd40BitRC2CBC = "1.2.840.113549.1.12.1.6";
111 public const string keyBag = "1.2.840.113549.1.12.10.1.1";
112 public const string pkcs8ShroudedKeyBag = "1.2.840.113549.1.12.10.1.2";
113 public const string certBag = "1.2.840.113549.1.12.10.1.3";
114 public const string crlBag = "1.2.840.113549.1.12.10.1.4";
115 public const string secretBag = "1.2.840.113549.1.12.10.1.5";
116 public const string safeContentsBag = "1.2.840.113549.1.12.10.1.6";
119 public const string x509Certificate = "1.2.840.113549.1.9.22.1";
120 public const string sdsiCertificate = "1.2.840.113549.1.9.22.2";
121 public const string x509Crl = "1.2.840.113549.1.9.23.1";
123 // Adapted from BouncyCastle PKCS12ParametersGenerator.java
124 public class DeriveBytes {
126 public enum Purpose {
132 static private byte[] keyDiversifier = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
133 static private byte[] ivDiversifier = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 };
134 static private byte[] macDiversifier = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 };
136 private string _hashName;
137 private int _iterations;
138 private byte[] _password;
139 private byte[] _salt;
141 public DeriveBytes () {}
143 public string HashName {
144 get { return _hashName; }
145 set { _hashName = value; }
148 public int IterationCount {
149 get { return _iterations; }
150 set { _iterations = value; }
153 public byte[] Password {
154 get { return (byte[]) _password.Clone (); }
157 _password = new byte [0];
159 _password = (byte[]) value.Clone ();
164 get { return (byte[]) _salt.Clone (); }
167 _salt = (byte[]) value.Clone ();
173 private void Adjust (byte[] a, int aOff, byte[] b)
175 int x = (b[b.Length - 1] & 0xff) + (a [aOff + b.Length - 1] & 0xff) + 1;
177 a [aOff + b.Length - 1] = (byte) x;
180 for (int i = b.Length - 2; i >= 0; i--) {
181 x += (b [i] & 0xff) + (a [aOff + i] & 0xff);
182 a [aOff + i] = (byte) x;
187 private byte[] Derive (byte[] diversifier, int n)
189 HashAlgorithm digest = HashAlgorithm.Create (_hashName);
190 int u = (digest.HashSize >> 3); // div 8
192 byte[] dKey = new byte [n];
195 if ((_salt != null) && (_salt.Length != 0)) {
196 S = new byte[v * ((_salt.Length + v - 1) / v)];
198 for (int i = 0; i != S.Length; i++) {
199 S[i] = _salt[i % _salt.Length];
207 if ((_password != null) && (_password.Length != 0)) {
208 P = new byte[v * ((_password.Length + v - 1) / v)];
210 for (int i = 0; i != P.Length; i++) {
211 P[i] = _password[i % _password.Length];
218 byte[] I = new byte [S.Length + P.Length];
220 Buffer.BlockCopy (S, 0, I, 0, S.Length);
221 Buffer.BlockCopy (P, 0, I, S.Length, P.Length);
223 byte[] B = new byte[v];
224 int c = (n + u - 1) / u;
226 for (int i = 1; i <= c; i++) {
227 digest.TransformBlock (diversifier, 0, diversifier.Length, diversifier, 0);
228 digest.TransformFinalBlock (I, 0, I.Length);
229 byte[] A = digest.Hash;
230 digest.Initialize ();
231 for (int j = 1; j != _iterations; j++) {
232 A = digest.ComputeHash (A, 0, A.Length);
235 for (int j = 0; j != B.Length; j++) {
236 B [j] = A [j % A.Length];
239 for (int j = 0; j != I.Length / v; j++) {
240 Adjust (I, j * v, B);
244 Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
247 Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, A.Length);
254 public byte[] DeriveKey (int size)
256 return Derive (keyDiversifier, size);
259 public byte[] DeriveIV (int size)
261 return Derive (ivDiversifier, size);
264 public byte[] DeriveMAC (int size)
266 return Derive (macDiversifier, size);
270 static private int recommendedIterationCount = 2000;
272 //private int _version;
273 private byte[] _password;
274 private ArrayList _keyBags;
275 private X509CertificateCollection _certs;
276 private bool _keyBagsChanged;
277 private bool _certsChanged;
278 private int _iterations;
279 private ArrayList _safeBags;
280 private RandomNumberGenerator _rng;
286 _iterations = recommendedIterationCount;
287 _keyBags = new ArrayList ();
288 _certs = new X509CertificateCollection ();
289 _keyBagsChanged = false;
290 _certsChanged = false;
291 _safeBags = new ArrayList ();
294 public PKCS12 (byte[] data)
303 * version INTEGER {v3(3)}(v3,...),
304 * authSafe ContentInfo,
305 * macData MacData OPTIONAL
308 * MacData ::= SEQUENCE {
310 * macSalt OCTET STRING,
311 * iterations INTEGER DEFAULT 1
312 * -- Note: The default is for historical reasons and its use is deprecated. A higher
313 * -- value, like 1024 is recommended.
316 * SafeContents ::= SEQUENCE OF SafeBag
318 * SafeBag ::= SEQUENCE {
319 * bagId BAG-TYPE.&id ({PKCS12BagSet}),
320 * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
321 * bagAttributes SET OF PKCS12Attribute OPTIONAL
324 public PKCS12 (byte[] data, string password)
331 public PKCS12 (byte[] data, byte[] password)
334 _password = password;
338 private void Decode (byte[] data)
340 ASN1 pfx = new ASN1 (data);
342 throw new ArgumentException ("invalid data");
344 ASN1 version = pfx [0];
345 if (version.Tag != 0x02)
346 throw new ArgumentException ("invalid PFX version");
347 //_version = version.Value [0];
349 PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (pfx [1]);
350 if (authSafe.ContentType != PKCS7.Oid.data)
351 throw new ArgumentException ("invalid authenticated safe");
353 // now that we know it's a PKCS#12 file, check the (optional) MAC
354 // before decoding anything else in the file
356 ASN1 macData = pfx [2];
357 if (macData.Tag != 0x30)
358 throw new ArgumentException ("invalid MAC");
360 ASN1 mac = macData [0];
362 throw new ArgumentException ("invalid MAC");
363 ASN1 macAlgorithm = mac [0];
364 string macOid = ASN1Convert.ToOid (macAlgorithm [0]);
365 if (macOid != "1.3.14.3.2.26")
366 throw new ArgumentException ("unsupported HMAC");
367 byte[] macValue = mac [1].Value;
369 ASN1 macSalt = macData [1];
370 if (macSalt.Tag != 0x04)
371 throw new ArgumentException ("missing MAC salt");
373 _iterations = 1; // default value
374 if (macData.Count > 2) {
375 ASN1 iters = macData [2];
376 if (iters.Tag != 0x02)
377 throw new ArgumentException ("invalid MAC iteration");
378 _iterations = ASN1Convert.ToInt32 (iters);
381 byte[] authSafeData = authSafe.Content [0].Value;
382 byte[] calculatedMac = MAC (_password, macSalt.Value, _iterations, authSafeData);
383 if (!Compare (macValue, calculatedMac))
384 throw new CryptographicException ("Invalid MAC - file may have been tampered!");
387 // we now returns to our original presentation - PFX
388 ASN1 authenticatedSafe = new ASN1 (authSafe.Content [0].Value);
389 for (int i=0; i < authenticatedSafe.Count; i++) {
390 PKCS7.ContentInfo ci = new PKCS7.ContentInfo (authenticatedSafe [i]);
391 switch (ci.ContentType) {
393 // unencrypted (by PKCS#12)
394 ASN1 safeContents = new ASN1 (ci.Content [0].Value);
395 for (int j=0; j < safeContents.Count; j++) {
396 ASN1 safeBag = safeContents [j];
397 ReadSafeBag (safeBag);
400 case PKCS7.Oid.encryptedData:
401 // password encrypted
402 PKCS7.EncryptedData ed = new PKCS7.EncryptedData (ci.Content [0]);
403 ASN1 decrypted = new ASN1 (Decrypt (ed));
404 for (int j=0; j < decrypted.Count; j++) {
405 ASN1 safeBag = decrypted [j];
406 ReadSafeBag (safeBag);
409 case PKCS7.Oid.envelopedData:
410 // public key encrypted
411 throw new NotImplementedException ("public key encrypted");
413 throw new ArgumentException ("unknown authenticatedSafe");
420 if (_password != null) {
421 Array.Clear (_password, 0, _password.Length);
428 public string Password {
431 if (value.EndsWith ("\0"))
432 _password = Encoding.BigEndianUnicode.GetBytes (value);
434 _password = Encoding.BigEndianUnicode.GetBytes (value + "\0");
437 _password = null; // no password
441 public int IterationCount {
442 get { return _iterations; }
443 set { _iterations = value; }
446 public ArrayList Keys {
448 if (_keyBagsChanged) {
450 foreach (SafeBag sb in _safeBags) {
451 if (sb.BagOID.Equals (keyBag)) {
452 ASN1 safeBag = sb.ASN1;
453 ASN1 bagValue = safeBag [1];
454 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
455 byte[] privateKey = pki.PrivateKey;
456 switch (privateKey [0]) {
458 DSAParameters p = new DSAParameters (); // FIXME
459 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
462 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
467 Array.Clear (privateKey, 0, privateKey.Length);
469 } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
470 ASN1 safeBag = sb.ASN1;
471 ASN1 bagValue = safeBag [1];
472 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
473 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
474 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
475 byte[] privateKey = pki.PrivateKey;
476 switch (privateKey [0]) {
478 DSAParameters p = new DSAParameters (); // FIXME
479 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
482 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
487 Array.Clear (privateKey, 0, privateKey.Length);
488 Array.Clear (decrypted, 0, decrypted.Length);
491 _keyBagsChanged = false;
493 return ArrayList.ReadOnly(_keyBags);
497 public X509CertificateCollection Certificates {
501 foreach (SafeBag sb in _safeBags) {
502 if (sb.BagOID.Equals (certBag)) {
503 ASN1 safeBag = sb.ASN1;
504 ASN1 bagValue = safeBag [1];
505 PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
506 _certs.Add (new X509Certificate (cert.Content [0].Value));
509 _certsChanged = false;
515 internal RandomNumberGenerator RNG {
518 _rng = RandomNumberGenerator.Create ();
525 private bool Compare (byte[] expected, byte[] actual)
527 bool compare = false;
528 if (expected.Length == actual.Length) {
529 for (int i=0; i < expected.Length; i++) {
530 if (expected [i] != actual [i])
538 private SymmetricAlgorithm GetSymmetricAlgorithm (string algorithmOid, byte[] salt, int iterationCount)
540 string algorithm = null;
541 int keyLength = 8; // 64 bits (default)
542 int ivLength = 8; // 64 bits (default)
544 PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
545 pd.Password = _password;
547 pd.IterationCount = iterationCount;
549 switch (algorithmOid) {
550 case PKCS5.pbeWithMD2AndDESCBC: // no unit test available
554 case PKCS5.pbeWithMD5AndDESCBC: // no unit test available
558 case PKCS5.pbeWithMD2AndRC2CBC: // no unit test available
559 // TODO - RC2-CBC-Parameter (PKCS5)
560 // if missing default to 32 bits !!!
563 keyLength = 4; // default
565 case PKCS5.pbeWithMD5AndRC2CBC: // no unit test available
566 // TODO - RC2-CBC-Parameter (PKCS5)
567 // if missing default to 32 bits !!!
570 keyLength = 4; // default
572 case PKCS5.pbeWithSHA1AndDESCBC: // no unit test available
573 pd.HashName = "SHA1";
576 case PKCS5.pbeWithSHA1AndRC2CBC: // no unit test available
577 // TODO - RC2-CBC-Parameter (PKCS5)
578 // if missing default to 32 bits !!!
579 pd.HashName = "SHA1";
581 keyLength = 4; // default
583 case PKCS12.pbeWithSHAAnd128BitRC4: // no unit test available
584 pd.HashName = "SHA1";
589 case PKCS12.pbeWithSHAAnd40BitRC4: // no unit test available
590 pd.HashName = "SHA1";
595 case PKCS12.pbeWithSHAAnd3KeyTripleDESCBC:
596 pd.HashName = "SHA1";
597 algorithm = "TripleDES";
600 case PKCS12.pbeWithSHAAnd2KeyTripleDESCBC: // no unit test available
601 pd.HashName = "SHA1";
602 algorithm = "TripleDES";
605 case PKCS12.pbeWithSHAAnd128BitRC2CBC: // no unit test available
606 pd.HashName = "SHA1";
610 case PKCS12.pbeWithSHAAnd40BitRC2CBC:
611 pd.HashName = "SHA1";
616 throw new NotSupportedException ("unknown oid " + algorithm);
619 SymmetricAlgorithm sa = SymmetricAlgorithm.Create (algorithm);
620 sa.Key = pd.DeriveKey (keyLength);
621 // IV required only for block ciphers (not stream ciphers)
623 sa.IV = pd.DeriveIV (ivLength);
624 sa.Mode = CipherMode.CBC;
629 public byte[] Decrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] encryptedData)
631 SymmetricAlgorithm sa = null;
632 byte[] result = null;
634 sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount);
635 ICryptoTransform ct = sa.CreateDecryptor ();
636 result = ct.TransformFinalBlock (encryptedData, 0, encryptedData.Length);
645 public byte[] Decrypt (PKCS7.EncryptedData ed)
647 return Decrypt (ed.EncryptionAlgorithm.ContentType,
648 ed.EncryptionAlgorithm.Content [0].Value,
649 ASN1Convert.ToInt32 (ed.EncryptionAlgorithm.Content [1]),
650 ed.EncryptedContent);
653 public byte[] Encrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] data)
655 byte[] result = null;
656 using (SymmetricAlgorithm sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount)) {
657 ICryptoTransform ct = sa.CreateEncryptor ();
658 result = ct.TransformFinalBlock (data, 0, data.Length);
663 private void AddPrivateKey (PKCS8.PrivateKeyInfo pki)
665 byte[] privateKey = pki.PrivateKey;
666 switch (privateKey [0]) {
668 DSAParameters p = new DSAParameters (); // FIXME
669 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
672 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
675 Array.Clear (privateKey, 0, privateKey.Length);
676 throw new CryptographicException ("Unknown private key format");
678 Array.Clear (privateKey, 0, privateKey.Length);
681 private void ReadSafeBag (ASN1 safeBag)
683 if (safeBag.Tag != 0x30)
684 throw new ArgumentException ("invalid safeBag");
686 ASN1 bagId = safeBag [0];
687 if (bagId.Tag != 0x06)
688 throw new ArgumentException ("invalid safeBag id");
690 ASN1 bagValue = safeBag [1];
691 string oid = ASN1Convert.ToOid (bagId);
695 AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value));
697 case pkcs8ShroudedKeyBag:
698 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
699 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
700 AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted));
701 Array.Clear (decrypted, 0, decrypted.Length);
704 PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
705 if (cert.ContentType != x509Certificate)
706 throw new NotSupportedException ("unsupport certificate type");
707 X509Certificate x509 = new X509Certificate (cert.Content [0].Value);
716 case safeContentsBag:
717 // TODO - ? recurse ?
720 throw new ArgumentException ("unknown safeBag oid");
723 if (safeBag.Count > 2) {
724 ASN1 bagAttributes = safeBag [2];
725 if (bagAttributes.Tag != 0x31)
726 throw new ArgumentException ("invalid safeBag attributes id");
728 for (int i = 0; i < bagAttributes.Count; i++) {
729 ASN1 pkcs12Attribute = bagAttributes[i];
731 if (pkcs12Attribute.Tag != 0x30)
732 throw new ArgumentException ("invalid PKCS12 attributes id");
734 ASN1 attrId = pkcs12Attribute [0];
735 if (attrId.Tag != 0x06)
736 throw new ArgumentException ("invalid attribute id");
738 string attrOid = ASN1Convert.ToOid (attrId);
740 ASN1 attrValues = pkcs12Attribute[1];
741 for (int j = 0; j < attrValues.Count; j++) {
742 ASN1 attrValue = attrValues[j];
745 case PKCS9.friendlyName:
746 if (attrValue.Tag != 0x1e)
747 throw new ArgumentException ("invalid attribute value id");
749 case PKCS9.localKeyId:
750 if (attrValue.Tag != 0x04)
751 throw new ArgumentException ("invalid attribute value id");
754 // Unknown OID -- don't check Tag
761 _safeBags.Add (new SafeBag(oid, safeBag));
764 private ASN1 Pkcs8ShroudedKeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
766 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
768 pki.Algorithm = "1.2.840.113549.1.1.1";
769 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
771 else if (aa is DSA) {
772 pki.Algorithm = null;
773 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
776 throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
778 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo ();
779 epki.Algorithm = pbeWithSHAAnd3KeyTripleDESCBC;
780 epki.IterationCount = _iterations;
781 epki.EncryptedData = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, epki.Salt, _iterations, pki.GetBytes ());
783 ASN1 safeBag = new ASN1 (0x30);
784 safeBag.Add (ASN1Convert.FromOid (pkcs8ShroudedKeyBag));
785 ASN1 bagValue = new ASN1 (0xA0);
786 bagValue.Add (new ASN1 (epki.GetBytes ()));
787 safeBag.Add (bagValue);
789 if (attributes != null) {
790 ASN1 bagAttributes = new ASN1 (0x31);
791 IDictionaryEnumerator de = attributes.GetEnumerator ();
793 while (de.MoveNext ()) {
794 string oid = (string)de.Key;
796 case PKCS9.friendlyName:
797 ArrayList names = (ArrayList)de.Value;
798 if (names.Count > 0) {
799 ASN1 pkcs12Attribute = new ASN1 (0x30);
800 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
801 ASN1 attrValues = new ASN1 (0x31);
802 foreach (byte[] name in names) {
803 ASN1 attrValue = new ASN1 (0x1e);
804 attrValue.Value = name;
805 attrValues.Add (attrValue);
807 pkcs12Attribute.Add (attrValues);
808 bagAttributes.Add (pkcs12Attribute);
811 case PKCS9.localKeyId:
812 ArrayList keys = (ArrayList)de.Value;
813 if (keys.Count > 0) {
814 ASN1 pkcs12Attribute = new ASN1 (0x30);
815 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
816 ASN1 attrValues = new ASN1 (0x31);
817 foreach (byte[] key in keys) {
818 ASN1 attrValue = new ASN1 (0x04);
819 attrValue.Value = key;
820 attrValues.Add (attrValue);
822 pkcs12Attribute.Add (attrValues);
823 bagAttributes.Add (pkcs12Attribute);
831 if (bagAttributes.Count > 0) {
832 safeBag.Add (bagAttributes);
839 private ASN1 KeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
841 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
843 pki.Algorithm = "1.2.840.113549.1.1.1";
844 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
846 else if (aa is DSA) {
847 pki.Algorithm = null;
848 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
851 throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
853 ASN1 safeBag = new ASN1 (0x30);
854 safeBag.Add (ASN1Convert.FromOid (keyBag));
855 ASN1 bagValue = new ASN1 (0xA0);
856 bagValue.Add (new ASN1 (pki.GetBytes ()));
857 safeBag.Add (bagValue);
859 if (attributes != null) {
860 ASN1 bagAttributes = new ASN1 (0x31);
861 IDictionaryEnumerator de = attributes.GetEnumerator ();
863 while (de.MoveNext ()) {
864 string oid = (string)de.Key;
866 case PKCS9.friendlyName:
867 ArrayList names = (ArrayList)de.Value;
868 if (names.Count > 0) {
869 ASN1 pkcs12Attribute = new ASN1 (0x30);
870 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
871 ASN1 attrValues = new ASN1 (0x31);
872 foreach (byte[] name in names) {
873 ASN1 attrValue = new ASN1 (0x1e);
874 attrValue.Value = name;
875 attrValues.Add (attrValue);
877 pkcs12Attribute.Add (attrValues);
878 bagAttributes.Add (pkcs12Attribute);
881 case PKCS9.localKeyId:
882 ArrayList keys = (ArrayList)de.Value;
883 if (keys.Count > 0) {
884 ASN1 pkcs12Attribute = new ASN1 (0x30);
885 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
886 ASN1 attrValues = new ASN1 (0x31);
887 foreach (byte[] key in keys) {
888 ASN1 attrValue = new ASN1 (0x04);
889 attrValue.Value = key;
890 attrValues.Add (attrValue);
892 pkcs12Attribute.Add (attrValues);
893 bagAttributes.Add (pkcs12Attribute);
901 if (bagAttributes.Count > 0) {
902 safeBag.Add (bagAttributes);
909 private ASN1 CertificateSafeBag (X509Certificate x509, IDictionary attributes)
911 ASN1 encapsulatedCertificate = new ASN1 (0x04, x509.RawData);
913 PKCS7.ContentInfo ci = new PKCS7.ContentInfo ();
914 ci.ContentType = x509Certificate;
915 ci.Content.Add (encapsulatedCertificate);
917 ASN1 bagValue = new ASN1 (0xA0);
918 bagValue.Add (ci.ASN1);
920 ASN1 safeBag = new ASN1 (0x30);
921 safeBag.Add (ASN1Convert.FromOid (certBag));
922 safeBag.Add (bagValue);
924 if (attributes != null) {
925 ASN1 bagAttributes = new ASN1 (0x31);
926 IDictionaryEnumerator de = attributes.GetEnumerator ();
928 while (de.MoveNext ()) {
929 string oid = (string)de.Key;
931 case PKCS9.friendlyName:
932 ArrayList names = (ArrayList)de.Value;
933 if (names.Count > 0) {
934 ASN1 pkcs12Attribute = new ASN1 (0x30);
935 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
936 ASN1 attrValues = new ASN1 (0x31);
937 foreach (byte[] name in names) {
938 ASN1 attrValue = new ASN1 (0x1e);
939 attrValue.Value = name;
940 attrValues.Add (attrValue);
942 pkcs12Attribute.Add (attrValues);
943 bagAttributes.Add (pkcs12Attribute);
946 case PKCS9.localKeyId:
947 ArrayList keys = (ArrayList)de.Value;
948 if (keys.Count > 0) {
949 ASN1 pkcs12Attribute = new ASN1 (0x30);
950 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
951 ASN1 attrValues = new ASN1 (0x31);
952 foreach (byte[] key in keys) {
953 ASN1 attrValue = new ASN1 (0x04);
954 attrValue.Value = key;
955 attrValues.Add (attrValue);
957 pkcs12Attribute.Add (attrValues);
958 bagAttributes.Add (pkcs12Attribute);
966 if (bagAttributes.Count > 0) {
967 safeBag.Add (bagAttributes);
974 private byte[] MAC (byte[] password, byte[] salt, int iterations, byte[] data)
976 PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
977 pd.HashName = "SHA1";
978 pd.Password = password;
980 pd.IterationCount = iterations;
982 HMACSHA1 hmac = (HMACSHA1) HMACSHA1.Create ();
983 hmac.Key = pd.DeriveMAC (20);
984 return hmac.ComputeHash (data, 0, data.Length);
988 * SafeContents ::= SEQUENCE OF SafeBag
990 * SafeBag ::= SEQUENCE {
991 * bagId BAG-TYPE.&id ({PKCS12BagSet}),
992 * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
993 * bagAttributes SET OF PKCS12Attribute OPTIONAL
996 public byte[] GetBytes ()
999 ASN1 safeBagSequence = new ASN1 (0x30);
1001 // Sync Safe Bag list since X509CertificateCollection may be updated
1002 ArrayList scs = new ArrayList ();
1003 foreach (SafeBag sb in _safeBags) {
1004 if (sb.BagOID.Equals (certBag)) {
1005 ASN1 safeBag = sb.ASN1;
1006 ASN1 bagValue = safeBag [1];
1007 PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
1008 scs.Add (new X509Certificate (cert.Content [0].Value));
1012 ArrayList addcerts = new ArrayList ();
1013 ArrayList removecerts = new ArrayList ();
1015 foreach (X509Certificate c in Certificates) {
1018 foreach (X509Certificate lc in scs) {
1019 if (Compare (c.RawData, lc.RawData)) {
1028 foreach (X509Certificate c in scs) {
1031 foreach (X509Certificate lc in Certificates) {
1032 if (Compare (c.RawData, lc.RawData)) {
1038 removecerts.Add (c);
1042 foreach (X509Certificate c in removecerts) {
1043 RemoveCertificate (c);
1046 foreach (X509Certificate c in addcerts) {
1051 if (_safeBags.Count > 0) {
1052 ASN1 certsSafeBag = new ASN1 (0x30);
1053 foreach (SafeBag sb in _safeBags) {
1054 if (sb.BagOID.Equals (certBag)) {
1055 certsSafeBag.Add (sb.ASN1);
1059 if (certsSafeBag.Count > 0) {
1060 byte[] certsSalt = new byte [8];
1061 RNG.GetBytes (certsSalt);
1063 ASN1 seqParams = new ASN1 (0x30);
1064 seqParams.Add (new ASN1 (0x04, certsSalt));
1065 seqParams.Add (ASN1Convert.FromInt32 (_iterations));
1067 ASN1 seqPbe = new ASN1 (0x30);
1068 seqPbe.Add (ASN1Convert.FromOid (pbeWithSHAAnd3KeyTripleDESCBC));
1069 seqPbe.Add (seqParams);
1071 byte[] encrypted = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, certsSalt, _iterations, certsSafeBag.GetBytes ());
1072 ASN1 encryptedCerts = new ASN1 (0x80, encrypted);
1074 ASN1 seq = new ASN1 (0x30);
1075 seq.Add (ASN1Convert.FromOid (PKCS7.Oid.data));
1077 seq.Add (encryptedCerts);
1079 ASN1 certsVersion = new ASN1 (0x02, new byte [1] { 0x00 });
1080 ASN1 encData = new ASN1 (0x30);
1081 encData.Add (certsVersion);
1084 ASN1 certsContent = new ASN1 (0xA0);
1085 certsContent.Add (encData);
1087 PKCS7.ContentInfo bag = new PKCS7.ContentInfo (PKCS7.Oid.encryptedData);
1088 bag.Content = certsContent;
1089 safeBagSequence.Add (bag.ASN1);
1093 if (_safeBags.Count > 0) {
1094 ASN1 safeContents = new ASN1 (0x30);
1095 foreach (SafeBag sb in _safeBags) {
1096 if (sb.BagOID.Equals (keyBag) ||
1097 sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1098 safeContents.Add (sb.ASN1);
1101 if (safeContents.Count > 0) {
1102 ASN1 content = new ASN1 (0xA0);
1103 content.Add (new ASN1 (0x04, safeContents.GetBytes ()));
1105 PKCS7.ContentInfo keyBag = new PKCS7.ContentInfo (PKCS7.Oid.data);
1106 keyBag.Content = content;
1107 safeBagSequence.Add (keyBag.ASN1);
1112 ASN1 encapsulates = new ASN1 (0x04, safeBagSequence.GetBytes ());
1113 ASN1 ci = new ASN1 (0xA0);
1114 ci.Add (encapsulates);
1115 PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (PKCS7.Oid.data);
1116 authSafe.Content = ci;
1118 ASN1 macData = new ASN1 (0x30);
1119 if (_password != null) {
1120 // only for password based encryption
1121 byte[] salt = new byte [20];
1122 RNG.GetBytes (salt);
1123 byte[] macValue = MAC (_password, salt, _iterations, authSafe.Content [0].Value);
1124 ASN1 oidSeq = new ASN1 (0x30);
1125 oidSeq.Add (ASN1Convert.FromOid ("1.3.14.3.2.26")); // SHA1
1126 oidSeq.Add (new ASN1 (0x05));
1128 ASN1 mac = new ASN1 (0x30);
1130 mac.Add (new ASN1 (0x04, macValue));
1133 macData.Add (new ASN1 (0x04, salt));
1134 macData.Add (ASN1Convert.FromInt32 (_iterations));
1137 ASN1 version = new ASN1 (0x02, new byte [1] { 0x03 });
1139 ASN1 pfx = new ASN1 (0x30);
1141 pfx.Add (authSafe.ASN1);
1142 if (macData.Count > 0) {
1143 // only for password based encryption
1147 return pfx.GetBytes ();
1150 public void AddCertificate (X509Certificate cert)
1152 AddCertificate (cert, null);
1155 public void AddCertificate (X509Certificate cert, IDictionary attributes)
1159 for (int i = 0; !found && i < _safeBags.Count; i++) {
1160 SafeBag sb = (SafeBag)_safeBags [i];
1162 if (sb.BagOID.Equals (certBag)) {
1163 ASN1 safeBag = sb.ASN1;
1164 ASN1 bagValue = safeBag [1];
1165 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1166 X509Certificate c = new X509Certificate (crt.Content [0].Value);
1167 if (Compare (cert.RawData, c.RawData)) {
1174 _safeBags.Add (new SafeBag (certBag, CertificateSafeBag (cert, attributes)));
1175 _certsChanged = true;
1179 public void RemoveCertificate (X509Certificate cert)
1181 RemoveCertificate (cert, null);
1184 public void RemoveCertificate (X509Certificate cert, IDictionary attrs)
1188 for (int i = 0; certIndex == -1 && i < _safeBags.Count; i++) {
1189 SafeBag sb = (SafeBag)_safeBags [i];
1191 if (sb.BagOID.Equals (certBag)) {
1192 ASN1 safeBag = sb.ASN1;
1193 ASN1 bagValue = safeBag [1];
1194 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1195 X509Certificate c = new X509Certificate (crt.Content [0].Value);
1196 if (Compare (cert.RawData, c.RawData)) {
1197 if (attrs != null) {
1198 if (safeBag.Count == 3) {
1199 ASN1 bagAttributes = safeBag [2];
1200 int bagAttributesFound = 0;
1201 for (int j = 0; j < bagAttributes.Count; j++) {
1202 ASN1 pkcs12Attribute = bagAttributes [j];
1203 ASN1 attrId = pkcs12Attribute [0];
1204 string ao = ASN1Convert.ToOid (attrId);
1205 ArrayList dattrValues = (ArrayList)attrs [ao];
1207 if (dattrValues != null) {
1208 ASN1 attrValues = pkcs12Attribute [1];
1210 if (dattrValues.Count == attrValues.Count) {
1211 int attrValuesFound = 0;
1212 for (int k = 0; k < attrValues.Count; k++) {
1213 ASN1 attrValue = attrValues [k];
1214 byte[] value = (byte[])dattrValues [k];
1216 if (Compare (value, attrValue.Value)) {
1217 attrValuesFound += 1;
1220 if (attrValuesFound == attrValues.Count) {
1221 bagAttributesFound += 1;
1226 if (bagAttributesFound == bagAttributes.Count) {
1237 if (certIndex != -1) {
1238 _safeBags.RemoveAt (certIndex);
1239 _certsChanged = true;
1243 private bool CompareAsymmetricAlgorithm (AsymmetricAlgorithm a1, AsymmetricAlgorithm a2)
1245 bool result = a1.KeyExchangeAlgorithm.Equals (a2.KeyExchangeAlgorithm);
1246 result = result && a1.KeySize == a2.KeySize;
1248 KeySizes[] keysizes = a2.LegalKeySizes;
1249 if (a1.LegalKeySizes.Length != keysizes.Length)
1252 for (int i = 0; i < a1.LegalKeySizes.Length; i++) {
1253 result = result && CompareKeySizes (a1.LegalKeySizes [i], keysizes [i]);
1256 result = result && a1.SignatureAlgorithm == a2.SignatureAlgorithm;
1261 private bool CompareKeySizes (KeySizes k1, KeySizes k2)
1263 bool result = k1.MaxSize == k2.MaxSize;
1264 result = result && k1.MinSize == k2.MinSize;
1265 result = result && k1.SkipSize == k2.SkipSize;
1269 public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
1271 AddPkcs8ShroudedKeyBag (aa, null);
1274 public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
1278 for (int i = 0; !found && i < _safeBags.Count; i++) {
1279 SafeBag sb = (SafeBag)_safeBags [i];
1281 if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1282 ASN1 bagValue = sb.ASN1 [1];
1283 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1284 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1285 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
1286 byte[] privateKey = pki.PrivateKey;
1288 AsymmetricAlgorithm saa = null;
1289 switch (privateKey [0]) {
1291 DSAParameters p = new DSAParameters (); // FIXME
1292 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1295 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1298 Array.Clear (decrypted, 0, decrypted.Length);
1299 Array.Clear (privateKey, 0, privateKey.Length);
1300 throw new CryptographicException ("Unknown private key format");
1303 Array.Clear (decrypted, 0, decrypted.Length);
1304 Array.Clear (privateKey, 0, privateKey.Length);
1306 if (CompareAsymmetricAlgorithm (aa , saa)) {
1313 _safeBags.Add (new SafeBag (pkcs8ShroudedKeyBag, Pkcs8ShroudedKeyBagSafeBag (aa, attributes)));
1314 _keyBagsChanged = true;
1318 public void RemovePkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
1322 for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
1323 SafeBag sb = (SafeBag)_safeBags [i];
1325 if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1326 ASN1 bagValue = sb.ASN1 [1];
1327 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1328 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1329 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
1330 byte[] privateKey = pki.PrivateKey;
1332 AsymmetricAlgorithm saa = null;
1333 switch (privateKey [0]) {
1335 DSAParameters p = new DSAParameters (); // FIXME
1336 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1339 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1342 Array.Clear (decrypted, 0, decrypted.Length);
1343 Array.Clear (privateKey, 0, privateKey.Length);
1344 throw new CryptographicException ("Unknown private key format");
1347 Array.Clear (decrypted, 0, decrypted.Length);
1348 Array.Clear (privateKey, 0, privateKey.Length);
1350 if (CompareAsymmetricAlgorithm (aa, saa)) {
1356 if (aaIndex != -1) {
1357 _safeBags.RemoveAt (aaIndex);
1358 _keyBagsChanged = true;
1362 public void AddKeyBag (AsymmetricAlgorithm aa)
1364 AddKeyBag (aa, null);
1367 public void AddKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
1371 for (int i = 0; !found && i < _safeBags.Count; i++) {
1372 SafeBag sb = (SafeBag)_safeBags [i];
1374 if (sb.BagOID.Equals (keyBag)) {
1375 ASN1 bagValue = sb.ASN1 [1];
1376 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1377 byte[] privateKey = pki.PrivateKey;
1379 AsymmetricAlgorithm saa = null;
1380 switch (privateKey [0]) {
1382 DSAParameters p = new DSAParameters (); // FIXME
1383 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1386 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1389 Array.Clear (privateKey, 0, privateKey.Length);
1390 throw new CryptographicException ("Unknown private key format");
1393 Array.Clear (privateKey, 0, privateKey.Length);
1395 if (CompareAsymmetricAlgorithm (aa, saa)) {
1402 _safeBags.Add (new SafeBag (keyBag, KeyBagSafeBag (aa, attributes)));
1403 _keyBagsChanged = true;
1407 public void RemoveKeyBag (AsymmetricAlgorithm aa)
1411 for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
1412 SafeBag sb = (SafeBag)_safeBags [i];
1414 if (sb.BagOID.Equals (keyBag)) {
1415 ASN1 bagValue = sb.ASN1 [1];
1416 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1417 byte[] privateKey = pki.PrivateKey;
1419 AsymmetricAlgorithm saa = null;
1420 switch (privateKey [0]) {
1422 DSAParameters p = new DSAParameters (); // FIXME
1423 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1426 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1429 Array.Clear (privateKey, 0, privateKey.Length);
1430 throw new CryptographicException ("Unknown private key format");
1433 Array.Clear (privateKey, 0, privateKey.Length);
1435 if (CompareAsymmetricAlgorithm (aa, saa)) {
1441 if (aaIndex != -1) {
1442 _safeBags.RemoveAt (aaIndex);
1443 _keyBagsChanged = true;
1448 public AsymmetricAlgorithm GetAsymmetricAlgorithm (IDictionary attrs)
1450 foreach (SafeBag sb in _safeBags) {
1451 if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1452 ASN1 safeBag = sb.ASN1;
1454 if (safeBag.Count == 3) {
1455 ASN1 bagAttributes = safeBag [2];
1457 int bagAttributesFound = 0;
1458 for (int i = 0; i < bagAttributes.Count; i++) {
1459 ASN1 pkcs12Attribute = bagAttributes [i];
1460 ASN1 attrId = pkcs12Attribute [0];
1461 string ao = ASN1Convert.ToOid (attrId);
1462 ArrayList dattrValues = (ArrayList)attrs [ao];
1464 if (dattrValues != null) {
1465 ASN1 attrValues = pkcs12Attribute [1];
1467 if (dattrValues.Count == attrValues.Count) {
1468 int attrValuesFound = 0;
1469 for (int j = 0; j < attrValues.Count; j++) {
1470 ASN1 attrValue = attrValues [j];
1471 byte[] value = (byte[])dattrValues [j];
1473 if (Compare (value, attrValue.Value)) {
1474 attrValuesFound += 1;
1477 if (attrValuesFound == attrValues.Count) {
1478 bagAttributesFound += 1;
1483 if (bagAttributesFound == bagAttributes.Count) {
1484 ASN1 bagValue = safeBag [1];
1485 AsymmetricAlgorithm aa = null;
1486 if (sb.BagOID.Equals (keyBag)) {
1487 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1488 byte[] privateKey = pki.PrivateKey;
1489 switch (privateKey [0]) {
1491 DSAParameters p = new DSAParameters (); // FIXME
1492 aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1495 aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1500 Array.Clear (privateKey, 0, privateKey.Length);
1501 } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1502 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1503 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1504 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
1505 byte[] privateKey = pki.PrivateKey;
1506 switch (privateKey [0]) {
1508 DSAParameters p = new DSAParameters (); // FIXME
1509 aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1512 aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1517 Array.Clear (privateKey, 0, privateKey.Length);
1518 Array.Clear (decrypted, 0, decrypted.Length);
1529 public X509Certificate GetCertificate (IDictionary attrs)
1531 foreach (SafeBag sb in _safeBags) {
1532 if (sb.BagOID.Equals (certBag)) {
1533 ASN1 safeBag = sb.ASN1;
1535 if (safeBag.Count == 3) {
1536 ASN1 bagAttributes = safeBag [2];
1538 int bagAttributesFound = 0;
1539 for (int i = 0; i < bagAttributes.Count; i++) {
1540 ASN1 pkcs12Attribute = bagAttributes [i];
1541 ASN1 attrId = pkcs12Attribute [0];
1542 string ao = ASN1Convert.ToOid (attrId);
1543 ArrayList dattrValues = (ArrayList)attrs [ao];
1545 if (dattrValues != null) {
1546 ASN1 attrValues = pkcs12Attribute [1];
1548 if (dattrValues.Count == attrValues.Count) {
1549 int attrValuesFound = 0;
1550 for (int j = 0; j < attrValues.Count; j++) {
1551 ASN1 attrValue = attrValues [j];
1552 byte[] value = (byte[])dattrValues [j];
1554 if (Compare (value, attrValue.Value)) {
1555 attrValuesFound += 1;
1558 if (attrValuesFound == attrValues.Count) {
1559 bagAttributesFound += 1;
1564 if (bagAttributesFound == bagAttributes.Count) {
1565 ASN1 bagValue = safeBag [1];
1566 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1567 return new X509Certificate (crt.Content [0].Value);
1576 public IDictionary GetAttributes (AsymmetricAlgorithm aa)
1578 IDictionary result = new Hashtable ();
1580 foreach (SafeBag sb in _safeBags) {
1581 if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1582 ASN1 safeBag = sb.ASN1;
1584 ASN1 bagValue = safeBag [1];
1585 AsymmetricAlgorithm saa = null;
1586 if (sb.BagOID.Equals (keyBag)) {
1587 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1588 byte[] privateKey = pki.PrivateKey;
1589 switch (privateKey [0]) {
1591 DSAParameters p = new DSAParameters (); // FIXME
1592 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1595 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1600 Array.Clear (privateKey, 0, privateKey.Length);
1601 } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1602 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1603 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1604 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
1605 byte[] privateKey = pki.PrivateKey;
1606 switch (privateKey [0]) {
1608 DSAParameters p = new DSAParameters (); // FIXME
1609 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1612 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1617 Array.Clear (privateKey, 0, privateKey.Length);
1618 Array.Clear (decrypted, 0, decrypted.Length);
1621 if (saa != null && CompareAsymmetricAlgorithm (saa, aa)) {
1622 if (safeBag.Count == 3) {
1623 ASN1 bagAttributes = safeBag [2];
1625 for (int i = 0; i < bagAttributes.Count; i++) {
1626 ASN1 pkcs12Attribute = bagAttributes [i];
1627 ASN1 attrId = pkcs12Attribute [0];
1628 string aOid = ASN1Convert.ToOid (attrId);
1629 ArrayList aValues = new ArrayList ();
1631 ASN1 attrValues = pkcs12Attribute [1];
1633 for (int j = 0; j < attrValues.Count; j++) {
1634 ASN1 attrValue = attrValues [j];
1635 aValues.Add (attrValue.Value);
1637 result.Add (aOid, aValues);
1647 public IDictionary GetAttributes (X509Certificate cert)
1649 IDictionary result = new Hashtable ();
1651 foreach (SafeBag sb in _safeBags) {
1652 if (sb.BagOID.Equals (certBag)) {
1653 ASN1 safeBag = sb.ASN1;
1654 ASN1 bagValue = safeBag [1];
1655 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1656 X509Certificate xc = new X509Certificate (crt.Content [0].Value);
1658 if (Compare (cert.RawData, xc.RawData)) {
1659 if (safeBag.Count == 3) {
1660 ASN1 bagAttributes = safeBag [2];
1662 for (int i = 0; i < bagAttributes.Count; i++) {
1663 ASN1 pkcs12Attribute = bagAttributes [i];
1664 ASN1 attrId = pkcs12Attribute [0];
1666 string aOid = ASN1Convert.ToOid (attrId);
1667 ArrayList aValues = new ArrayList ();
1669 ASN1 attrValues = pkcs12Attribute [1];
1671 for (int j = 0; j < attrValues.Count; j++) {
1672 ASN1 attrValue = attrValues [j];
1673 aValues.Add (attrValue.Value);
1675 result.Add (aOid, aValues);
1685 public void SaveToFile (string filename)
1687 if (filename == null)
1688 throw new ArgumentNullException ("filename");
1690 using (FileStream fs = File.OpenWrite (filename)) {
1691 byte[] data = GetBytes ();
1692 fs.Write (data, 0, data.Length);
1698 public object Clone ()
1700 PKCS12 clone = null;
1701 if (_password != null) {
1702 clone = new PKCS12 (GetBytes (), Encoding.BigEndianUnicode.GetString (_password));
1704 clone = new PKCS12 (GetBytes ());
1706 clone.IterationCount = this.IterationCount;
1713 static private byte[] LoadFile (string filename)
1716 using (FileStream fs = File.OpenRead (filename)) {
1717 data = new byte [fs.Length];
1718 fs.Read (data, 0, data.Length);
1724 static public PKCS12 LoadFromFile (string filename)
1726 if (filename == null)
1727 throw new ArgumentNullException ("filename");
1729 return new PKCS12 (LoadFile (filename));
1732 static public PKCS12 LoadFromFile (string filename, string password)
1734 if (filename == null)
1735 throw new ArgumentNullException ("filename");
1737 return new PKCS12 (LoadFile (filename), password);