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) : this (data, null) {}
298 * version INTEGER {v3(3)}(v3,...),
299 * authSafe ContentInfo,
300 * macData MacData OPTIONAL
303 * MacData ::= SEQUENCE {
305 * macSalt OCTET STRING,
306 * iterations INTEGER DEFAULT 1
307 * -- Note: The default is for historical reasons and its use is deprecated. A higher
308 * -- value, like 1024 is recommended.
311 * SafeContents ::= SEQUENCE OF SafeBag
313 * SafeBag ::= SEQUENCE {
314 * bagId BAG-TYPE.&id ({PKCS12BagSet}),
315 * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
316 * bagAttributes SET OF PKCS12Attribute OPTIONAL
319 public PKCS12 (byte[] data, string password) : this ()
323 ASN1 pfx = new ASN1 (data);
325 throw new ArgumentException ("invalid data");
327 ASN1 version = pfx [0];
328 if (version.Tag != 0x02)
329 throw new ArgumentException ("invalid PFX version");
330 _version = version.Value [0];
332 PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (pfx [1]);
333 if (authSafe.ContentType != PKCS7.Oid.data)
334 throw new ArgumentException ("invalid authenticated safe");
336 // now that we know it's a PKCS#12 file, check the (optional) MAC
337 // before decoding anything else in the file
339 ASN1 macData = pfx [2];
340 if (macData.Tag != 0x30)
341 throw new ArgumentException ("invalid MAC");
343 ASN1 mac = macData [0];
345 throw new ArgumentException ("invalid MAC");
346 ASN1 macAlgorithm = mac [0];
347 string macOid = ASN1Convert.ToOid (macAlgorithm [0]);
348 if (macOid != "1.3.14.3.2.26")
349 throw new ArgumentException ("unsupported HMAC");
350 byte[] macValue = mac [1].Value;
352 ASN1 macSalt = macData [1];
353 if (macSalt.Tag != 0x04)
354 throw new ArgumentException ("missing MAC salt");
356 _iterations = 1; // default value
357 if (macData.Count > 2) {
358 ASN1 iters = macData [2];
359 if (iters.Tag != 0x02)
360 throw new ArgumentException ("invalid MAC iteration");
361 _iterations = ASN1Convert.ToInt32 (iters);
364 byte[] authSafeData = authSafe.Content [0].Value;
365 byte[] calculatedMac = MAC (_password, macSalt.Value, _iterations, authSafeData);
366 if (!Compare (macValue, calculatedMac))
367 throw new CryptographicException ("Invalid MAC - file may have been tampered!");
370 // we now returns to our original presentation - PFX
371 ASN1 authenticatedSafe = new ASN1 (authSafe.Content [0].Value);
372 for (int i=0; i < authenticatedSafe.Count; i++) {
373 PKCS7.ContentInfo ci = new PKCS7.ContentInfo (authenticatedSafe [i]);
374 switch (ci.ContentType) {
376 // unencrypted (by PKCS#12)
377 ASN1 safeContents = new ASN1 (ci.Content [0].Value);
378 for (int j=0; j < safeContents.Count; j++) {
379 ASN1 safeBag = safeContents [j];
380 ReadSafeBag (safeBag);
383 case PKCS7.Oid.encryptedData:
384 // password encrypted
385 PKCS7.EncryptedData ed = new PKCS7.EncryptedData (ci.Content [0]);
386 ASN1 decrypted = new ASN1 (Decrypt (ed));
387 for (int j=0; j < decrypted.Count; j++) {
388 ASN1 safeBag = decrypted [j];
389 ReadSafeBag (safeBag);
392 case PKCS7.Oid.envelopedData:
393 // public key encrypted
394 throw new NotImplementedException ("public key encrypted");
396 throw new ArgumentException ("unknown authenticatedSafe");
403 if (_password != null) {
404 Array.Clear (_password, 0, _password.Length);
411 public string Password {
414 if (value.EndsWith ("\0"))
415 _password = Encoding.BigEndianUnicode.GetBytes (value);
417 _password = Encoding.BigEndianUnicode.GetBytes (value + "\0");
420 _password = null; // no password
424 public int IterationCount {
425 get { return _iterations; }
426 set { _iterations = value; }
429 public ArrayList Keys {
431 if (_keyBagsChanged) {
433 foreach (SafeBag sb in _safeBags) {
434 if (sb.BagOID.Equals (keyBag)) {
435 ASN1 safeBag = sb.ASN1;
436 ASN1 bagValue = safeBag [1];
437 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
438 byte[] privateKey = pki.PrivateKey;
439 switch (privateKey [0]) {
441 DSAParameters p = new DSAParameters (); // FIXME
442 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
445 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
450 Array.Clear (privateKey, 0, privateKey.Length);
452 } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
453 ASN1 safeBag = sb.ASN1;
454 ASN1 bagValue = safeBag [1];
455 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
456 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
457 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
458 byte[] privateKey = pki.PrivateKey;
459 switch (privateKey [0]) {
461 DSAParameters p = new DSAParameters (); // FIXME
462 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
465 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
470 Array.Clear (privateKey, 0, privateKey.Length);
471 Array.Clear (decrypted, 0, decrypted.Length);
474 _keyBagsChanged = false;
476 return ArrayList.ReadOnly(_keyBags);
480 public X509CertificateCollection Certificates {
484 foreach (SafeBag sb in _safeBags) {
485 if (sb.BagOID.Equals (certBag)) {
486 ASN1 safeBag = sb.ASN1;
487 ASN1 bagValue = safeBag [1];
488 PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
489 _certs.Add (new X509Certificate (cert.Content [0].Value));
492 _certsChanged = false;
498 internal RandomNumberGenerator RNG {
501 _rng = RandomNumberGenerator.Create ();
508 private bool Compare (byte[] expected, byte[] actual)
510 bool compare = false;
511 if (expected.Length == actual.Length) {
512 for (int i=0; i < expected.Length; i++) {
513 if (expected [i] != actual [i])
521 private SymmetricAlgorithm GetSymmetricAlgorithm (string algorithmOid, byte[] salt, int iterationCount)
523 string algorithm = null;
524 int keyLength = 8; // 64 bits (default)
525 int ivLength = 8; // 64 bits (default)
527 PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
528 pd.Password = _password;
530 pd.IterationCount = iterationCount;
532 switch (algorithmOid) {
533 case PKCS5.pbeWithMD2AndDESCBC: // no unit test available
537 case PKCS5.pbeWithMD5AndDESCBC: // no unit test available
541 case PKCS5.pbeWithMD2AndRC2CBC: // no unit test available
542 // TODO - RC2-CBC-Parameter (PKCS5)
543 // if missing default to 32 bits !!!
546 keyLength = 4; // default
548 case PKCS5.pbeWithMD5AndRC2CBC: // no unit test available
549 // TODO - RC2-CBC-Parameter (PKCS5)
550 // if missing default to 32 bits !!!
553 keyLength = 4; // default
555 case PKCS5.pbeWithSHA1AndDESCBC: // no unit test available
556 pd.HashName = "SHA1";
559 case PKCS5.pbeWithSHA1AndRC2CBC: // no unit test available
560 // TODO - RC2-CBC-Parameter (PKCS5)
561 // if missing default to 32 bits !!!
562 pd.HashName = "SHA1";
564 keyLength = 4; // default
566 case PKCS12.pbeWithSHAAnd128BitRC4: // no unit test available
567 pd.HashName = "SHA1";
572 case PKCS12.pbeWithSHAAnd40BitRC4: // no unit test available
573 pd.HashName = "SHA1";
578 case PKCS12.pbeWithSHAAnd3KeyTripleDESCBC:
579 pd.HashName = "SHA1";
580 algorithm = "TripleDES";
583 case PKCS12.pbeWithSHAAnd2KeyTripleDESCBC: // no unit test available
584 pd.HashName = "SHA1";
585 algorithm = "TripleDES";
588 case PKCS12.pbeWithSHAAnd128BitRC2CBC: // no unit test available
589 pd.HashName = "SHA1";
593 case PKCS12.pbeWithSHAAnd40BitRC2CBC:
594 pd.HashName = "SHA1";
599 throw new NotSupportedException ("unknown oid " + algorithm);
602 SymmetricAlgorithm sa = SymmetricAlgorithm.Create (algorithm);
603 sa.Key = pd.DeriveKey (keyLength);
604 // IV required only for block ciphers (not stream ciphers)
606 sa.IV = pd.DeriveIV (ivLength);
607 sa.Mode = CipherMode.CBC;
612 public byte[] Decrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] encryptedData)
614 SymmetricAlgorithm sa = null;
615 byte[] result = null;
617 sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount);
618 ICryptoTransform ct = sa.CreateDecryptor ();
619 result = ct.TransformFinalBlock (encryptedData, 0, encryptedData.Length);
628 public byte[] Decrypt (PKCS7.EncryptedData ed)
630 return Decrypt (ed.EncryptionAlgorithm.ContentType,
631 ed.EncryptionAlgorithm.Content [0].Value,
632 ASN1Convert.ToInt32 (ed.EncryptionAlgorithm.Content [1]),
633 ed.EncryptedContent);
636 public byte[] Encrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] data)
638 byte[] result = null;
639 using (SymmetricAlgorithm sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount)) {
640 ICryptoTransform ct = sa.CreateEncryptor ();
641 result = ct.TransformFinalBlock (data, 0, data.Length);
646 private void AddPrivateKey (PKCS8.PrivateKeyInfo pki)
648 byte[] privateKey = pki.PrivateKey;
649 switch (privateKey [0]) {
651 DSAParameters p = new DSAParameters (); // FIXME
652 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
655 _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
658 Array.Clear (privateKey, 0, privateKey.Length);
659 throw new CryptographicException ("Unknown private key format");
661 Array.Clear (privateKey, 0, privateKey.Length);
664 private void ReadSafeBag (ASN1 safeBag)
666 if (safeBag.Tag != 0x30)
667 throw new ArgumentException ("invalid safeBag");
669 ASN1 bagId = safeBag [0];
670 if (bagId.Tag != 0x06)
671 throw new ArgumentException ("invalid safeBag id");
673 ASN1 bagValue = safeBag [1];
674 string oid = ASN1Convert.ToOid (bagId);
678 AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value));
680 case pkcs8ShroudedKeyBag:
681 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
682 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
683 AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted));
684 Array.Clear (decrypted, 0, decrypted.Length);
687 PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
688 if (cert.ContentType != x509Certificate)
689 throw new NotSupportedException ("unsupport certificate type");
690 X509Certificate x509 = new X509Certificate (cert.Content [0].Value);
699 case safeContentsBag:
700 // TODO - ? recurse ?
703 throw new ArgumentException ("unknown safeBag oid");
706 if (safeBag.Count > 2) {
707 ASN1 bagAttributes = safeBag [2];
708 if (bagAttributes.Tag != 0x31)
709 throw new ArgumentException ("invalid safeBag attributes id");
711 for (int i = 0; i < bagAttributes.Count; i++) {
712 ASN1 pkcs12Attribute = bagAttributes[i];
714 if (pkcs12Attribute.Tag != 0x30)
715 throw new ArgumentException ("invalid PKCS12 attributes id");
717 ASN1 attrId = pkcs12Attribute [0];
718 if (attrId.Tag != 0x06)
719 throw new ArgumentException ("invalid attribute id");
721 string attrOid = ASN1Convert.ToOid (attrId);
723 ASN1 attrValues = pkcs12Attribute[1];
724 for (int j = 0; j < attrValues.Count; j++) {
725 ASN1 attrValue = attrValues[j];
728 case PKCS9.friendlyName:
729 if (attrValue.Tag != 0x1e)
730 throw new ArgumentException ("invalid attribute value id");
732 case PKCS9.localKeyId:
733 if (attrValue.Tag != 0x04)
734 throw new ArgumentException ("invalid attribute value id");
737 // Unknown OID -- don't check Tag
744 _safeBags.Add (new SafeBag(oid, safeBag));
747 private ASN1 Pkcs8ShroudedKeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
749 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
751 pki.Algorithm = "1.2.840.113549.1.1.1";
752 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
754 else if (aa is DSA) {
755 pki.Algorithm = null;
756 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
759 throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
761 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo ();
762 epki.Algorithm = pbeWithSHAAnd3KeyTripleDESCBC;
763 epki.IterationCount = _iterations;
764 epki.EncryptedData = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, epki.Salt, _iterations, pki.GetBytes ());
766 ASN1 safeBag = new ASN1 (0x30);
767 safeBag.Add (ASN1Convert.FromOid (pkcs8ShroudedKeyBag));
768 ASN1 bagValue = new ASN1 (0xA0);
769 bagValue.Add (new ASN1 (epki.GetBytes ()));
770 safeBag.Add (bagValue);
772 if (attributes != null) {
773 ASN1 bagAttributes = new ASN1 (0x31);
774 IDictionaryEnumerator de = attributes.GetEnumerator ();
776 while (de.MoveNext ()) {
777 string oid = (string)de.Key;
779 case PKCS9.friendlyName:
780 ArrayList names = (ArrayList)de.Value;
781 if (names.Count > 0) {
782 ASN1 pkcs12Attribute = new ASN1 (0x30);
783 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
784 ASN1 attrValues = new ASN1 (0x31);
785 foreach (byte[] name in names) {
786 ASN1 attrValue = new ASN1 (0x1e);
787 attrValue.Value = name;
788 attrValues.Add (attrValue);
790 pkcs12Attribute.Add (attrValues);
791 bagAttributes.Add (pkcs12Attribute);
794 case PKCS9.localKeyId:
795 ArrayList keys = (ArrayList)de.Value;
796 if (keys.Count > 0) {
797 ASN1 pkcs12Attribute = new ASN1 (0x30);
798 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
799 ASN1 attrValues = new ASN1 (0x31);
800 foreach (byte[] key in keys) {
801 ASN1 attrValue = new ASN1 (0x04);
802 attrValue.Value = key;
803 attrValues.Add (attrValue);
805 pkcs12Attribute.Add (attrValues);
806 bagAttributes.Add (pkcs12Attribute);
814 if (bagAttributes.Count > 0) {
815 safeBag.Add (bagAttributes);
822 private ASN1 KeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
824 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
826 pki.Algorithm = "1.2.840.113549.1.1.1";
827 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
829 else if (aa is DSA) {
830 pki.Algorithm = null;
831 pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
834 throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
836 ASN1 safeBag = new ASN1 (0x30);
837 safeBag.Add (ASN1Convert.FromOid (keyBag));
838 ASN1 bagValue = new ASN1 (0xA0);
839 bagValue.Add (new ASN1 (pki.GetBytes ()));
840 safeBag.Add (bagValue);
842 if (attributes != null) {
843 ASN1 bagAttributes = new ASN1 (0x31);
844 IDictionaryEnumerator de = attributes.GetEnumerator ();
846 while (de.MoveNext ()) {
847 string oid = (string)de.Key;
849 case PKCS9.friendlyName:
850 ArrayList names = (ArrayList)de.Value;
851 if (names.Count > 0) {
852 ASN1 pkcs12Attribute = new ASN1 (0x30);
853 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
854 ASN1 attrValues = new ASN1 (0x31);
855 foreach (byte[] name in names) {
856 ASN1 attrValue = new ASN1 (0x1e);
857 attrValue.Value = name;
858 attrValues.Add (attrValue);
860 pkcs12Attribute.Add (attrValues);
861 bagAttributes.Add (pkcs12Attribute);
864 case PKCS9.localKeyId:
865 ArrayList keys = (ArrayList)de.Value;
866 if (keys.Count > 0) {
867 ASN1 pkcs12Attribute = new ASN1 (0x30);
868 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
869 ASN1 attrValues = new ASN1 (0x31);
870 foreach (byte[] key in keys) {
871 ASN1 attrValue = new ASN1 (0x04);
872 attrValue.Value = key;
873 attrValues.Add (attrValue);
875 pkcs12Attribute.Add (attrValues);
876 bagAttributes.Add (pkcs12Attribute);
884 if (bagAttributes.Count > 0) {
885 safeBag.Add (bagAttributes);
892 private ASN1 CertificateSafeBag (X509Certificate x509, IDictionary attributes)
894 ASN1 encapsulatedCertificate = new ASN1 (0x04, x509.RawData);
896 PKCS7.ContentInfo ci = new PKCS7.ContentInfo ();
897 ci.ContentType = x509Certificate;
898 ci.Content.Add (encapsulatedCertificate);
900 ASN1 bagValue = new ASN1 (0xA0);
901 bagValue.Add (ci.ASN1);
903 ASN1 safeBag = new ASN1 (0x30);
904 safeBag.Add (ASN1Convert.FromOid (certBag));
905 safeBag.Add (bagValue);
907 if (attributes != null) {
908 ASN1 bagAttributes = new ASN1 (0x31);
909 IDictionaryEnumerator de = attributes.GetEnumerator ();
911 while (de.MoveNext ()) {
912 string oid = (string)de.Key;
914 case PKCS9.friendlyName:
915 ArrayList names = (ArrayList)de.Value;
916 if (names.Count > 0) {
917 ASN1 pkcs12Attribute = new ASN1 (0x30);
918 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
919 ASN1 attrValues = new ASN1 (0x31);
920 foreach (byte[] name in names) {
921 ASN1 attrValue = new ASN1 (0x1e);
922 attrValue.Value = name;
923 attrValues.Add (attrValue);
925 pkcs12Attribute.Add (attrValues);
926 bagAttributes.Add (pkcs12Attribute);
929 case PKCS9.localKeyId:
930 ArrayList keys = (ArrayList)de.Value;
931 if (keys.Count > 0) {
932 ASN1 pkcs12Attribute = new ASN1 (0x30);
933 pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
934 ASN1 attrValues = new ASN1 (0x31);
935 foreach (byte[] key in keys) {
936 ASN1 attrValue = new ASN1 (0x04);
937 attrValue.Value = key;
938 attrValues.Add (attrValue);
940 pkcs12Attribute.Add (attrValues);
941 bagAttributes.Add (pkcs12Attribute);
949 if (bagAttributes.Count > 0) {
950 safeBag.Add (bagAttributes);
957 private byte[] MAC (byte[] password, byte[] salt, int iterations, byte[] data)
959 PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
960 pd.HashName = "SHA1";
961 pd.Password = password;
963 pd.IterationCount = iterations;
965 HMACSHA1 hmac = (HMACSHA1) HMACSHA1.Create ();
966 hmac.Key = pd.DeriveMAC (20);
967 return hmac.ComputeHash (data, 0, data.Length);
971 * SafeContents ::= SEQUENCE OF SafeBag
973 * SafeBag ::= SEQUENCE {
974 * bagId BAG-TYPE.&id ({PKCS12BagSet}),
975 * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
976 * bagAttributes SET OF PKCS12Attribute OPTIONAL
979 public byte[] GetBytes ()
982 ASN1 safeBagSequence = new ASN1 (0x30);
984 // Sync Safe Bag list since X509CertificateCollection may be updated
985 ArrayList scs = new ArrayList ();
986 foreach (SafeBag sb in _safeBags) {
987 if (sb.BagOID.Equals (certBag)) {
988 ASN1 safeBag = sb.ASN1;
989 ASN1 bagValue = safeBag [1];
990 PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
991 scs.Add (new X509Certificate (cert.Content [0].Value));
995 ArrayList addcerts = new ArrayList ();
996 ArrayList removecerts = new ArrayList ();
998 foreach (X509Certificate c in Certificates) {
1001 foreach (X509Certificate lc in scs) {
1002 if (Compare (c.RawData, lc.RawData)) {
1011 foreach (X509Certificate c in scs) {
1014 foreach (X509Certificate lc in Certificates) {
1015 if (Compare (c.RawData, lc.RawData)) {
1021 removecerts.Add (c);
1025 foreach (X509Certificate c in removecerts) {
1026 RemoveCertificate (c);
1029 foreach (X509Certificate c in addcerts) {
1034 if (_safeBags.Count > 0) {
1035 ASN1 certsSafeBag = new ASN1 (0x30);
1036 foreach (SafeBag sb in _safeBags) {
1037 if (sb.BagOID.Equals (certBag)) {
1038 certsSafeBag.Add (sb.ASN1);
1042 if (certsSafeBag.Count > 0) {
1043 byte[] certsSalt = new byte [8];
1044 RNG.GetBytes (certsSalt);
1046 ASN1 seqParams = new ASN1 (0x30);
1047 seqParams.Add (new ASN1 (0x04, certsSalt));
1048 seqParams.Add (ASN1Convert.FromInt32 (_iterations));
1050 ASN1 seqPbe = new ASN1 (0x30);
1051 seqPbe.Add (ASN1Convert.FromOid (pbeWithSHAAnd3KeyTripleDESCBC));
1052 seqPbe.Add (seqParams);
1054 byte[] encrypted = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, certsSalt, _iterations, certsSafeBag.GetBytes ());
1055 ASN1 encryptedCerts = new ASN1 (0x80, encrypted);
1057 ASN1 seq = new ASN1 (0x30);
1058 seq.Add (ASN1Convert.FromOid (PKCS7.Oid.data));
1060 seq.Add (encryptedCerts);
1062 ASN1 certsVersion = new ASN1 (0x02, new byte [1] { 0x00 });
1063 ASN1 encData = new ASN1 (0x30);
1064 encData.Add (certsVersion);
1067 ASN1 certsContent = new ASN1 (0xA0);
1068 certsContent.Add (encData);
1070 PKCS7.ContentInfo bag = new PKCS7.ContentInfo (PKCS7.Oid.encryptedData);
1071 bag.Content = certsContent;
1072 safeBagSequence.Add (bag.ASN1);
1076 if (_safeBags.Count > 0) {
1077 ASN1 safeContents = new ASN1 (0x30);
1078 foreach (SafeBag sb in _safeBags) {
1079 if (sb.BagOID.Equals (keyBag) ||
1080 sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1081 safeContents.Add (sb.ASN1);
1084 if (safeContents.Count > 0) {
1085 ASN1 content = new ASN1 (0xA0);
1086 content.Add (new ASN1 (0x04, safeContents.GetBytes ()));
1088 PKCS7.ContentInfo keyBag = new PKCS7.ContentInfo (PKCS7.Oid.data);
1089 keyBag.Content = content;
1090 safeBagSequence.Add (keyBag.ASN1);
1095 ASN1 encapsulates = new ASN1 (0x04, safeBagSequence.GetBytes ());
1096 ASN1 ci = new ASN1 (0xA0);
1097 ci.Add (encapsulates);
1098 PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (PKCS7.Oid.data);
1099 authSafe.Content = ci;
1101 ASN1 macData = new ASN1 (0x30);
1102 if (_password != null) {
1103 // only for password based encryption
1104 byte[] salt = new byte [20];
1105 RNG.GetBytes (salt);
1106 byte[] macValue = MAC (_password, salt, _iterations, authSafe.Content [0].Value);
1107 ASN1 oidSeq = new ASN1 (0x30);
1108 oidSeq.Add (ASN1Convert.FromOid ("1.3.14.3.2.26")); // SHA1
1109 oidSeq.Add (new ASN1 (0x05));
1111 ASN1 mac = new ASN1 (0x30);
1113 mac.Add (new ASN1 (0x04, macValue));
1116 macData.Add (new ASN1 (0x04, salt));
1117 macData.Add (ASN1Convert.FromInt32 (_iterations));
1120 ASN1 version = new ASN1 (0x02, new byte [1] { 0x03 });
1122 ASN1 pfx = new ASN1 (0x30);
1124 pfx.Add (authSafe.ASN1);
1125 if (macData.Count > 0) {
1126 // only for password based encryption
1130 return pfx.GetBytes ();
1133 public void AddCertificate (X509Certificate cert)
1135 AddCertificate (cert, null);
1138 public void AddCertificate (X509Certificate cert, IDictionary attributes)
1142 for (int i = 0; !found && i < _safeBags.Count; i++) {
1143 SafeBag sb = (SafeBag)_safeBags [i];
1145 if (sb.BagOID.Equals (certBag)) {
1146 ASN1 safeBag = sb.ASN1;
1147 ASN1 bagValue = safeBag [1];
1148 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1149 X509Certificate c = new X509Certificate (crt.Content [0].Value);
1150 if (Compare (cert.RawData, c.RawData)) {
1157 _safeBags.Add (new SafeBag (certBag, CertificateSafeBag (cert, attributes)));
1158 _certsChanged = true;
1162 public void RemoveCertificate (X509Certificate cert)
1164 RemoveCertificate (cert, null);
1167 public void RemoveCertificate (X509Certificate cert, IDictionary attrs)
1171 for (int i = 0; certIndex == -1 && i < _safeBags.Count; i++) {
1172 SafeBag sb = (SafeBag)_safeBags [i];
1174 if (sb.BagOID.Equals (certBag)) {
1175 ASN1 safeBag = sb.ASN1;
1176 ASN1 bagValue = safeBag [1];
1177 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1178 X509Certificate c = new X509Certificate (crt.Content [0].Value);
1179 if (Compare (cert.RawData, c.RawData)) {
1180 if (attrs != null) {
1181 if (safeBag.Count == 3) {
1182 ASN1 bagAttributes = safeBag [2];
1183 int bagAttributesFound = 0;
1184 for (int j = 0; j < bagAttributes.Count; j++) {
1185 ASN1 pkcs12Attribute = bagAttributes [j];
1186 ASN1 attrId = pkcs12Attribute [0];
1187 string ao = ASN1Convert.ToOid (attrId);
1188 ArrayList dattrValues = (ArrayList)attrs [ao];
1190 if (dattrValues != null) {
1191 ASN1 attrValues = pkcs12Attribute [1];
1193 if (dattrValues.Count == attrValues.Count) {
1194 int attrValuesFound = 0;
1195 for (int k = 0; k < attrValues.Count; k++) {
1196 ASN1 attrValue = attrValues [k];
1197 byte[] value = (byte[])dattrValues [k];
1199 if (Compare (value, attrValue.Value)) {
1200 attrValuesFound += 1;
1203 if (attrValuesFound == attrValues.Count) {
1204 bagAttributesFound += 1;
1209 if (bagAttributesFound == bagAttributes.Count) {
1220 if (certIndex != -1) {
1221 _safeBags.RemoveAt (certIndex);
1222 _certsChanged = true;
1226 private bool CompareAsymmetricAlgorithm (AsymmetricAlgorithm a1, AsymmetricAlgorithm a2)
1228 bool result = a1.KeyExchangeAlgorithm.Equals (a2.KeyExchangeAlgorithm);
1229 result = result && a1.KeySize == a2.KeySize;
1231 KeySizes[] keysizes = a2.LegalKeySizes;
1232 if (a1.LegalKeySizes.Length != keysizes.Length)
1235 for (int i = 0; i < a1.LegalKeySizes.Length; i++) {
1236 result = result && CompareKeySizes (a1.LegalKeySizes [i], keysizes [i]);
1239 result = result && a1.SignatureAlgorithm == a2.SignatureAlgorithm;
1244 private bool CompareKeySizes (KeySizes k1, KeySizes k2)
1246 bool result = k1.MaxSize == k2.MaxSize;
1247 result = result && k1.MinSize == k2.MinSize;
1248 result = result && k1.SkipSize == k2.SkipSize;
1252 public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
1254 AddPkcs8ShroudedKeyBag (aa, null);
1257 public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
1261 for (int i = 0; !found && i < _safeBags.Count; i++) {
1262 SafeBag sb = (SafeBag)_safeBags [i];
1264 if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1265 ASN1 bagValue = sb.ASN1 [1];
1266 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1267 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1268 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
1269 byte[] privateKey = pki.PrivateKey;
1271 AsymmetricAlgorithm saa = null;
1272 switch (privateKey [0]) {
1274 DSAParameters p = new DSAParameters (); // FIXME
1275 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1278 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1281 Array.Clear (decrypted, 0, decrypted.Length);
1282 Array.Clear (privateKey, 0, privateKey.Length);
1283 throw new CryptographicException ("Unknown private key format");
1286 Array.Clear (decrypted, 0, decrypted.Length);
1287 Array.Clear (privateKey, 0, privateKey.Length);
1289 if (CompareAsymmetricAlgorithm (aa , saa)) {
1296 _safeBags.Add (new SafeBag (pkcs8ShroudedKeyBag, Pkcs8ShroudedKeyBagSafeBag (aa, attributes)));
1297 _keyBagsChanged = true;
1301 public void RemovePkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
1305 for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
1306 SafeBag sb = (SafeBag)_safeBags [i];
1308 if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1309 ASN1 bagValue = sb.ASN1 [1];
1310 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1311 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1312 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
1313 byte[] privateKey = pki.PrivateKey;
1315 AsymmetricAlgorithm saa = null;
1316 switch (privateKey [0]) {
1318 DSAParameters p = new DSAParameters (); // FIXME
1319 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1322 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1325 Array.Clear (decrypted, 0, decrypted.Length);
1326 Array.Clear (privateKey, 0, privateKey.Length);
1327 throw new CryptographicException ("Unknown private key format");
1330 Array.Clear (decrypted, 0, decrypted.Length);
1331 Array.Clear (privateKey, 0, privateKey.Length);
1333 if (CompareAsymmetricAlgorithm (aa, saa)) {
1339 if (aaIndex != -1) {
1340 _safeBags.RemoveAt (aaIndex);
1341 _keyBagsChanged = true;
1345 public void AddKeyBag (AsymmetricAlgorithm aa)
1347 AddKeyBag (aa, null);
1350 public void AddKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
1354 for (int i = 0; !found && i < _safeBags.Count; i++) {
1355 SafeBag sb = (SafeBag)_safeBags [i];
1357 if (sb.BagOID.Equals (keyBag)) {
1358 ASN1 bagValue = sb.ASN1 [1];
1359 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1360 byte[] privateKey = pki.PrivateKey;
1362 AsymmetricAlgorithm saa = null;
1363 switch (privateKey [0]) {
1365 DSAParameters p = new DSAParameters (); // FIXME
1366 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1369 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1372 Array.Clear (privateKey, 0, privateKey.Length);
1373 throw new CryptographicException ("Unknown private key format");
1376 Array.Clear (privateKey, 0, privateKey.Length);
1378 if (CompareAsymmetricAlgorithm (aa, saa)) {
1385 _safeBags.Add (new SafeBag (keyBag, KeyBagSafeBag (aa, attributes)));
1386 _keyBagsChanged = true;
1390 public void RemoveKeyBag (AsymmetricAlgorithm aa)
1394 for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
1395 SafeBag sb = (SafeBag)_safeBags [i];
1397 if (sb.BagOID.Equals (keyBag)) {
1398 ASN1 bagValue = sb.ASN1 [1];
1399 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1400 byte[] privateKey = pki.PrivateKey;
1402 AsymmetricAlgorithm saa = null;
1403 switch (privateKey [0]) {
1405 DSAParameters p = new DSAParameters (); // FIXME
1406 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1409 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1412 Array.Clear (privateKey, 0, privateKey.Length);
1413 throw new CryptographicException ("Unknown private key format");
1416 Array.Clear (privateKey, 0, privateKey.Length);
1418 if (CompareAsymmetricAlgorithm (aa, saa)) {
1424 if (aaIndex != -1) {
1425 _safeBags.RemoveAt (aaIndex);
1426 _keyBagsChanged = true;
1431 public AsymmetricAlgorithm GetAsymmetricAlgorithm (IDictionary attrs)
1433 foreach (SafeBag sb in _safeBags) {
1434 if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1435 ASN1 safeBag = sb.ASN1;
1437 if (safeBag.Count == 3) {
1438 ASN1 bagAttributes = safeBag [2];
1440 int bagAttributesFound = 0;
1441 for (int i = 0; i < bagAttributes.Count; i++) {
1442 ASN1 pkcs12Attribute = bagAttributes [i];
1443 ASN1 attrId = pkcs12Attribute [0];
1444 string ao = ASN1Convert.ToOid (attrId);
1445 ArrayList dattrValues = (ArrayList)attrs [ao];
1447 if (dattrValues != null) {
1448 ASN1 attrValues = pkcs12Attribute [1];
1450 if (dattrValues.Count == attrValues.Count) {
1451 int attrValuesFound = 0;
1452 for (int j = 0; j < attrValues.Count; j++) {
1453 ASN1 attrValue = attrValues [j];
1454 byte[] value = (byte[])dattrValues [j];
1456 if (Compare (value, attrValue.Value)) {
1457 attrValuesFound += 1;
1460 if (attrValuesFound == attrValues.Count) {
1461 bagAttributesFound += 1;
1466 if (bagAttributesFound == bagAttributes.Count) {
1467 ASN1 bagValue = safeBag [1];
1468 AsymmetricAlgorithm aa = null;
1469 if (sb.BagOID.Equals (keyBag)) {
1470 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1471 byte[] privateKey = pki.PrivateKey;
1472 switch (privateKey [0]) {
1474 DSAParameters p = new DSAParameters (); // FIXME
1475 aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1478 aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1483 Array.Clear (privateKey, 0, privateKey.Length);
1484 } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1485 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1486 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1487 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
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 Array.Clear (decrypted, 0, decrypted.Length);
1512 public X509Certificate GetCertificate (IDictionary attrs)
1514 foreach (SafeBag sb in _safeBags) {
1515 if (sb.BagOID.Equals (certBag)) {
1516 ASN1 safeBag = sb.ASN1;
1518 if (safeBag.Count == 3) {
1519 ASN1 bagAttributes = safeBag [2];
1521 int bagAttributesFound = 0;
1522 for (int i = 0; i < bagAttributes.Count; i++) {
1523 ASN1 pkcs12Attribute = bagAttributes [i];
1524 ASN1 attrId = pkcs12Attribute [0];
1525 string ao = ASN1Convert.ToOid (attrId);
1526 ArrayList dattrValues = (ArrayList)attrs [ao];
1528 if (dattrValues != null) {
1529 ASN1 attrValues = pkcs12Attribute [1];
1531 if (dattrValues.Count == attrValues.Count) {
1532 int attrValuesFound = 0;
1533 for (int j = 0; j < attrValues.Count; j++) {
1534 ASN1 attrValue = attrValues [j];
1535 byte[] value = (byte[])dattrValues [j];
1537 if (Compare (value, attrValue.Value)) {
1538 attrValuesFound += 1;
1541 if (attrValuesFound == attrValues.Count) {
1542 bagAttributesFound += 1;
1547 if (bagAttributesFound == bagAttributes.Count) {
1548 ASN1 bagValue = safeBag [1];
1549 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1550 return new X509Certificate (crt.Content [0].Value);
1559 public IDictionary GetAttributes (AsymmetricAlgorithm aa)
1561 IDictionary result = new Hashtable ();
1563 foreach (SafeBag sb in _safeBags) {
1564 if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1565 ASN1 safeBag = sb.ASN1;
1567 ASN1 bagValue = safeBag [1];
1568 AsymmetricAlgorithm saa = null;
1569 if (sb.BagOID.Equals (keyBag)) {
1570 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
1571 byte[] privateKey = pki.PrivateKey;
1572 switch (privateKey [0]) {
1574 DSAParameters p = new DSAParameters (); // FIXME
1575 saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
1578 saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
1583 Array.Clear (privateKey, 0, privateKey.Length);
1584 } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
1585 PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
1586 byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
1587 PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
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 Array.Clear (decrypted, 0, decrypted.Length);
1604 if (saa != null && CompareAsymmetricAlgorithm (saa, aa)) {
1605 if (safeBag.Count == 3) {
1606 ASN1 bagAttributes = safeBag [2];
1608 for (int i = 0; i < bagAttributes.Count; i++) {
1609 ASN1 pkcs12Attribute = bagAttributes [i];
1610 ASN1 attrId = pkcs12Attribute [0];
1611 string aOid = ASN1Convert.ToOid (attrId);
1612 ArrayList aValues = new ArrayList ();
1614 ASN1 attrValues = pkcs12Attribute [1];
1616 for (int j = 0; j < attrValues.Count; j++) {
1617 ASN1 attrValue = attrValues [j];
1618 aValues.Add (attrValue.Value);
1620 result.Add (aOid, aValues);
1630 public IDictionary GetAttributes (X509Certificate cert)
1632 IDictionary result = new Hashtable ();
1634 foreach (SafeBag sb in _safeBags) {
1635 if (sb.BagOID.Equals (certBag)) {
1636 ASN1 safeBag = sb.ASN1;
1637 ASN1 bagValue = safeBag [1];
1638 PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
1639 X509Certificate xc = new X509Certificate (crt.Content [0].Value);
1641 if (Compare (cert.RawData, xc.RawData)) {
1642 if (safeBag.Count == 3) {
1643 ASN1 bagAttributes = safeBag [2];
1645 for (int i = 0; i < bagAttributes.Count; i++) {
1646 ASN1 pkcs12Attribute = bagAttributes [i];
1647 ASN1 attrId = pkcs12Attribute [0];
1649 string aOid = ASN1Convert.ToOid (attrId);
1650 ArrayList aValues = new ArrayList ();
1652 ASN1 attrValues = pkcs12Attribute [1];
1654 for (int j = 0; j < attrValues.Count; j++) {
1655 ASN1 attrValue = attrValues [j];
1656 aValues.Add (attrValue.Value);
1658 result.Add (aOid, aValues);
1668 public void SaveToFile (string filename)
1670 if (filename == null)
1671 throw new ArgumentNullException ("filename");
1673 using (FileStream fs = File.OpenWrite (filename)) {
1674 byte[] data = GetBytes ();
1675 fs.Write (data, 0, data.Length);
1681 public object Clone ()
1683 PKCS12 clone = null;
1684 if (_password != null) {
1685 clone = new PKCS12 (GetBytes (), Encoding.BigEndianUnicode.GetString (_password));
1687 clone = new PKCS12 (GetBytes ());
1689 clone.IterationCount = this.IterationCount;
1696 static private byte[] LoadFile (string filename)
1699 using (FileStream fs = File.OpenRead (filename)) {
1700 data = new byte [fs.Length];
1701 fs.Read (data, 0, data.Length);
1707 static public PKCS12 LoadFromFile (string filename)
1709 if (filename == null)
1710 throw new ArgumentNullException ("filename");
1712 return new PKCS12 (LoadFile (filename));
1715 static public PKCS12 LoadFromFile (string filename, string password)
1717 if (filename == null)
1718 throw new ArgumentNullException ("filename");
1720 return new PKCS12 (LoadFile (filename), password);