PKCS12.cs 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933
  1. //
  2. // PKCS12.cs: PKCS 12 - Personal Information Exchange Syntax
  3. //
  4. // Author:
  5. // Sebastien Pouliot <sebastien@xamarin.com>
  6. //
  7. // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
  8. // Copyright (C) 2004,2005,2006 Novell Inc. (http://www.novell.com)
  9. // Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
  10. //
  11. // Key derivation translated from Bouncy Castle JCE (http://www.bouncycastle.org/)
  12. // See bouncycastle.txt for license.
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining
  15. // a copy of this software and associated documentation files (the
  16. // "Software"), to deal in the Software without restriction, including
  17. // without limitation the rights to use, copy, modify, merge, publish,
  18. // distribute, sublicense, and/or sell copies of the Software, and to
  19. // permit persons to whom the Software is furnished to do so, subject to
  20. // the following conditions:
  21. //
  22. // The above copyright notice and this permission notice shall be
  23. // included in all copies or substantial portions of the Software.
  24. //
  25. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  29. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  30. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  31. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. //
  33. using System;
  34. using System.Collections;
  35. using System.IO;
  36. using System.Security.Cryptography;
  37. using System.Text;
  38. namespace MediaBrowser.Server.Mono.Security {
  39. public class PKCS5 {
  40. public const string pbeWithMD2AndDESCBC = "1.2.840.113549.1.5.1";
  41. public const string pbeWithMD5AndDESCBC = "1.2.840.113549.1.5.3";
  42. public const string pbeWithMD2AndRC2CBC = "1.2.840.113549.1.5.4";
  43. public const string pbeWithMD5AndRC2CBC = "1.2.840.113549.1.5.6";
  44. public const string pbeWithSHA1AndDESCBC = "1.2.840.113549.1.5.10";
  45. public const string pbeWithSHA1AndRC2CBC = "1.2.840.113549.1.5.11";
  46. public PKCS5 () {}
  47. }
  48. public class PKCS9 {
  49. public const string friendlyName = "1.2.840.113549.1.9.20";
  50. public const string localKeyId = "1.2.840.113549.1.9.21";
  51. public PKCS9 () {}
  52. }
  53. internal class SafeBag {
  54. private string _bagOID;
  55. private ASN1 _asn1;
  56. public SafeBag(string bagOID, ASN1 asn1) {
  57. _bagOID = bagOID;
  58. _asn1 = asn1;
  59. }
  60. public string BagOID {
  61. get { return _bagOID; }
  62. }
  63. public ASN1 ASN1 {
  64. get { return _asn1; }
  65. }
  66. }
  67. public class PKCS12 : ICloneable {
  68. public const string pbeWithSHAAnd128BitRC4 = "1.2.840.113549.1.12.1.1";
  69. public const string pbeWithSHAAnd40BitRC4 = "1.2.840.113549.1.12.1.2";
  70. public const string pbeWithSHAAnd3KeyTripleDESCBC = "1.2.840.113549.1.12.1.3";
  71. public const string pbeWithSHAAnd2KeyTripleDESCBC = "1.2.840.113549.1.12.1.4";
  72. public const string pbeWithSHAAnd128BitRC2CBC = "1.2.840.113549.1.12.1.5";
  73. public const string pbeWithSHAAnd40BitRC2CBC = "1.2.840.113549.1.12.1.6";
  74. // bags
  75. public const string keyBag = "1.2.840.113549.1.12.10.1.1";
  76. public const string pkcs8ShroudedKeyBag = "1.2.840.113549.1.12.10.1.2";
  77. public const string certBag = "1.2.840.113549.1.12.10.1.3";
  78. public const string crlBag = "1.2.840.113549.1.12.10.1.4";
  79. public const string secretBag = "1.2.840.113549.1.12.10.1.5";
  80. public const string safeContentsBag = "1.2.840.113549.1.12.10.1.6";
  81. // types
  82. public const string x509Certificate = "1.2.840.113549.1.9.22.1";
  83. public const string sdsiCertificate = "1.2.840.113549.1.9.22.2";
  84. public const string x509Crl = "1.2.840.113549.1.9.23.1";
  85. // Adapted from BouncyCastle PKCS12ParametersGenerator.java
  86. public class DeriveBytes {
  87. public enum Purpose {
  88. Key,
  89. IV,
  90. MAC
  91. }
  92. 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 };
  93. 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 };
  94. 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 };
  95. private string _hashName;
  96. private int _iterations;
  97. private byte[] _password;
  98. private byte[] _salt;
  99. public DeriveBytes () {}
  100. public string HashName {
  101. get { return _hashName; }
  102. set { _hashName = value; }
  103. }
  104. public int IterationCount {
  105. get { return _iterations; }
  106. set { _iterations = value; }
  107. }
  108. public byte[] Password {
  109. get { return (byte[]) _password.Clone (); }
  110. set {
  111. if (value == null)
  112. _password = new byte [0];
  113. else
  114. _password = (byte[]) value.Clone ();
  115. }
  116. }
  117. public byte[] Salt {
  118. get { return (byte[]) _salt.Clone (); }
  119. set {
  120. if (value != null)
  121. _salt = (byte[]) value.Clone ();
  122. else
  123. _salt = null;
  124. }
  125. }
  126. private void Adjust (byte[] a, int aOff, byte[] b)
  127. {
  128. int x = (b[b.Length - 1] & 0xff) + (a [aOff + b.Length - 1] & 0xff) + 1;
  129. a [aOff + b.Length - 1] = (byte) x;
  130. x >>= 8;
  131. for (int i = b.Length - 2; i >= 0; i--) {
  132. x += (b [i] & 0xff) + (a [aOff + i] & 0xff);
  133. a [aOff + i] = (byte) x;
  134. x >>= 8;
  135. }
  136. }
  137. private byte[] Derive (byte[] diversifier, int n)
  138. {
  139. HashAlgorithm digest = PKCS1.CreateFromName (_hashName);
  140. int u = (digest.HashSize >> 3); // div 8
  141. int v = 64;
  142. byte[] dKey = new byte [n];
  143. byte[] S;
  144. if ((_salt != null) && (_salt.Length != 0)) {
  145. S = new byte[v * ((_salt.Length + v - 1) / v)];
  146. for (int i = 0; i != S.Length; i++) {
  147. S[i] = _salt[i % _salt.Length];
  148. }
  149. }
  150. else {
  151. S = new byte[0];
  152. }
  153. byte[] P;
  154. if ((_password != null) && (_password.Length != 0)) {
  155. P = new byte[v * ((_password.Length + v - 1) / v)];
  156. for (int i = 0; i != P.Length; i++) {
  157. P[i] = _password[i % _password.Length];
  158. }
  159. }
  160. else {
  161. P = new byte[0];
  162. }
  163. byte[] I = new byte [S.Length + P.Length];
  164. Buffer.BlockCopy (S, 0, I, 0, S.Length);
  165. Buffer.BlockCopy (P, 0, I, S.Length, P.Length);
  166. byte[] B = new byte[v];
  167. int c = (n + u - 1) / u;
  168. for (int i = 1; i <= c; i++) {
  169. digest.TransformBlock (diversifier, 0, diversifier.Length, diversifier, 0);
  170. digest.TransformFinalBlock (I, 0, I.Length);
  171. byte[] A = digest.Hash;
  172. digest.Initialize ();
  173. for (int j = 1; j != _iterations; j++) {
  174. A = digest.ComputeHash (A, 0, A.Length);
  175. }
  176. for (int j = 0; j != B.Length; j++) {
  177. B [j] = A [j % A.Length];
  178. }
  179. for (int j = 0; j != I.Length / v; j++) {
  180. Adjust (I, j * v, B);
  181. }
  182. if (i == c) {
  183. Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
  184. }
  185. else {
  186. Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, A.Length);
  187. }
  188. }
  189. return dKey;
  190. }
  191. public byte[] DeriveKey (int size)
  192. {
  193. return Derive (keyDiversifier, size);
  194. }
  195. public byte[] DeriveIV (int size)
  196. {
  197. return Derive (ivDiversifier, size);
  198. }
  199. public byte[] DeriveMAC (int size)
  200. {
  201. return Derive (macDiversifier, size);
  202. }
  203. }
  204. const int recommendedIterationCount = 2000;
  205. //private int _version;
  206. private byte[] _password;
  207. private ArrayList _keyBags;
  208. private ArrayList _secretBags;
  209. private X509CertificateCollection _certs;
  210. private bool _keyBagsChanged;
  211. private bool _secretBagsChanged;
  212. private bool _certsChanged;
  213. private int _iterations;
  214. private ArrayList _safeBags;
  215. private RandomNumberGenerator _rng;
  216. // constructors
  217. public PKCS12 ()
  218. {
  219. _iterations = recommendedIterationCount;
  220. _keyBags = new ArrayList ();
  221. _secretBags = new ArrayList ();
  222. _certs = new X509CertificateCollection ();
  223. _keyBagsChanged = false;
  224. _secretBagsChanged = false;
  225. _certsChanged = false;
  226. _safeBags = new ArrayList ();
  227. }
  228. public PKCS12 (byte[] data)
  229. : this ()
  230. {
  231. Password = null;
  232. Decode (data);
  233. }
  234. /*
  235. * PFX ::= SEQUENCE {
  236. * version INTEGER {v3(3)}(v3,...),
  237. * authSafe ContentInfo,
  238. * macData MacData OPTIONAL
  239. * }
  240. *
  241. * MacData ::= SEQUENCE {
  242. * mac DigestInfo,
  243. * macSalt OCTET STRING,
  244. * iterations INTEGER DEFAULT 1
  245. * -- Note: The default is for historical reasons and its use is deprecated. A higher
  246. * -- value, like 1024 is recommended.
  247. * }
  248. *
  249. * SafeContents ::= SEQUENCE OF SafeBag
  250. *
  251. * SafeBag ::= SEQUENCE {
  252. * bagId BAG-TYPE.&id ({PKCS12BagSet}),
  253. * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
  254. * bagAttributes SET OF PKCS12Attribute OPTIONAL
  255. * }
  256. */
  257. public PKCS12 (byte[] data, string password)
  258. : this ()
  259. {
  260. Password = password;
  261. Decode (data);
  262. }
  263. public PKCS12 (byte[] data, byte[] password)
  264. : this ()
  265. {
  266. _password = password;
  267. Decode (data);
  268. }
  269. private void Decode (byte[] data)
  270. {
  271. ASN1 pfx = new ASN1 (data);
  272. if (pfx.Tag != 0x30)
  273. throw new ArgumentException ("invalid data");
  274. ASN1 version = pfx [0];
  275. if (version.Tag != 0x02)
  276. throw new ArgumentException ("invalid PFX version");
  277. //_version = version.Value [0];
  278. PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (pfx [1]);
  279. if (authSafe.ContentType != PKCS7.Oid.data)
  280. throw new ArgumentException ("invalid authenticated safe");
  281. // now that we know it's a PKCS#12 file, check the (optional) MAC
  282. // before decoding anything else in the file
  283. if (pfx.Count > 2) {
  284. ASN1 macData = pfx [2];
  285. if (macData.Tag != 0x30)
  286. throw new ArgumentException ("invalid MAC");
  287. ASN1 mac = macData [0];
  288. if (mac.Tag != 0x30)
  289. throw new ArgumentException ("invalid MAC");
  290. ASN1 macAlgorithm = mac [0];
  291. string macOid = ASN1Convert.ToOid (macAlgorithm [0]);
  292. if (macOid != "1.3.14.3.2.26")
  293. throw new ArgumentException ("unsupported HMAC");
  294. byte[] macValue = mac [1].Value;
  295. ASN1 macSalt = macData [1];
  296. if (macSalt.Tag != 0x04)
  297. throw new ArgumentException ("missing MAC salt");
  298. _iterations = 1; // default value
  299. if (macData.Count > 2) {
  300. ASN1 iters = macData [2];
  301. if (iters.Tag != 0x02)
  302. throw new ArgumentException ("invalid MAC iteration");
  303. _iterations = ASN1Convert.ToInt32 (iters);
  304. }
  305. byte[] authSafeData = authSafe.Content [0].Value;
  306. byte[] calculatedMac = MAC (_password, macSalt.Value, _iterations, authSafeData);
  307. if (!Compare (macValue, calculatedMac)) {
  308. byte[] nullPassword = {0, 0};
  309. calculatedMac = MAC(nullPassword, macSalt.Value, _iterations, authSafeData);
  310. if (!Compare (macValue, calculatedMac))
  311. throw new CryptographicException ("Invalid MAC - file may have been tampe red!");
  312. _password = nullPassword;
  313. }
  314. }
  315. // we now returns to our original presentation - PFX
  316. ASN1 authenticatedSafe = new ASN1 (authSafe.Content [0].Value);
  317. for (int i=0; i < authenticatedSafe.Count; i++) {
  318. PKCS7.ContentInfo ci = new PKCS7.ContentInfo (authenticatedSafe [i]);
  319. switch (ci.ContentType) {
  320. case PKCS7.Oid.data:
  321. // unencrypted (by PKCS#12)
  322. ASN1 safeContents = new ASN1 (ci.Content [0].Value);
  323. for (int j=0; j < safeContents.Count; j++) {
  324. ASN1 safeBag = safeContents [j];
  325. ReadSafeBag (safeBag);
  326. }
  327. break;
  328. case PKCS7.Oid.encryptedData:
  329. // password encrypted
  330. PKCS7.EncryptedData ed = new PKCS7.EncryptedData (ci.Content [0]);
  331. ASN1 decrypted = new ASN1 (Decrypt (ed));
  332. for (int j=0; j < decrypted.Count; j++) {
  333. ASN1 safeBag = decrypted [j];
  334. ReadSafeBag (safeBag);
  335. }
  336. break;
  337. case PKCS7.Oid.envelopedData:
  338. // public key encrypted
  339. throw new NotImplementedException ("public key encrypted");
  340. default:
  341. throw new ArgumentException ("unknown authenticatedSafe");
  342. }
  343. }
  344. }
  345. ~PKCS12 ()
  346. {
  347. if (_password != null) {
  348. Array.Clear (_password, 0, _password.Length);
  349. }
  350. _password = null;
  351. }
  352. // properties
  353. public string Password {
  354. set {
  355. // Clear old password.
  356. if (_password != null)
  357. Array.Clear (_password, 0, _password.Length);
  358. _password = null;
  359. if (value != null) {
  360. if (value.Length > 0) {
  361. int size = value.Length;
  362. int nul = 0;
  363. if (size < MaximumPasswordLength) {
  364. // if not present, add space for a NULL (0x00) character
  365. if (value[size - 1] != 0x00)
  366. nul = 1;
  367. } else {
  368. size = MaximumPasswordLength;
  369. }
  370. _password = new byte[(size + nul) << 1]; // double for unicode
  371. Encoding.BigEndianUnicode.GetBytes (value, 0, size, _password, 0);
  372. } else {
  373. // double-byte (Unicode) NULL (0x00) - see bug #79617
  374. _password = new byte[2];
  375. }
  376. }
  377. }
  378. }
  379. public int IterationCount {
  380. get { return _iterations; }
  381. set { _iterations = value; }
  382. }
  383. public ArrayList Keys {
  384. get {
  385. if (_keyBagsChanged) {
  386. _keyBags.Clear ();
  387. foreach (SafeBag sb in _safeBags) {
  388. if (sb.BagOID.Equals (keyBag)) {
  389. ASN1 safeBag = sb.ASN1;
  390. ASN1 bagValue = safeBag [1];
  391. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
  392. byte[] privateKey = pki.PrivateKey;
  393. switch (privateKey [0]) {
  394. case 0x02:
  395. DSAParameters p = new DSAParameters (); // FIXME
  396. _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
  397. break;
  398. case 0x30:
  399. _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
  400. break;
  401. default:
  402. break;
  403. }
  404. Array.Clear (privateKey, 0, privateKey.Length);
  405. } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  406. ASN1 safeBag = sb.ASN1;
  407. ASN1 bagValue = safeBag [1];
  408. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
  409. byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
  410. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
  411. byte[] privateKey = pki.PrivateKey;
  412. switch (privateKey [0]) {
  413. case 0x02:
  414. DSAParameters p = new DSAParameters (); // FIXME
  415. _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
  416. break;
  417. case 0x30:
  418. _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
  419. break;
  420. default:
  421. break;
  422. }
  423. Array.Clear (privateKey, 0, privateKey.Length);
  424. Array.Clear (decrypted, 0, decrypted.Length);
  425. }
  426. }
  427. _keyBagsChanged = false;
  428. }
  429. return ArrayList.ReadOnly(_keyBags);
  430. }
  431. }
  432. public ArrayList Secrets {
  433. get {
  434. if (_secretBagsChanged) {
  435. _secretBags.Clear ();
  436. foreach (SafeBag sb in _safeBags) {
  437. if (sb.BagOID.Equals (secretBag)) {
  438. ASN1 safeBag = sb.ASN1;
  439. ASN1 bagValue = safeBag [1];
  440. byte[] secret = bagValue.Value;
  441. _secretBags.Add(secret);
  442. }
  443. }
  444. _secretBagsChanged = false;
  445. }
  446. return ArrayList.ReadOnly(_secretBags);
  447. }
  448. }
  449. public X509CertificateCollection Certificates {
  450. get {
  451. if (_certsChanged) {
  452. _certs.Clear ();
  453. foreach (SafeBag sb in _safeBags) {
  454. if (sb.BagOID.Equals (certBag)) {
  455. ASN1 safeBag = sb.ASN1;
  456. ASN1 bagValue = safeBag [1];
  457. PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
  458. _certs.Add (new X509Certificate (cert.Content [0].Value));
  459. }
  460. }
  461. _certsChanged = false;
  462. }
  463. return _certs;
  464. }
  465. }
  466. internal RandomNumberGenerator RNG {
  467. get {
  468. if (_rng == null)
  469. _rng = RandomNumberGenerator.Create ();
  470. return _rng;
  471. }
  472. }
  473. // private methods
  474. private bool Compare (byte[] expected, byte[] actual)
  475. {
  476. bool compare = false;
  477. if (expected.Length == actual.Length) {
  478. for (int i=0; i < expected.Length; i++) {
  479. if (expected [i] != actual [i])
  480. return false;
  481. }
  482. compare = true;
  483. }
  484. return compare;
  485. }
  486. private SymmetricAlgorithm GetSymmetricAlgorithm (string algorithmOid, byte[] salt, int iterationCount)
  487. {
  488. string algorithm = null;
  489. int keyLength = 8; // 64 bits (default)
  490. int ivLength = 8; // 64 bits (default)
  491. PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
  492. pd.Password = _password;
  493. pd.Salt = salt;
  494. pd.IterationCount = iterationCount;
  495. switch (algorithmOid) {
  496. case PKCS5.pbeWithMD2AndDESCBC: // no unit test available
  497. pd.HashName = "MD2";
  498. algorithm = "DES";
  499. break;
  500. case PKCS5.pbeWithMD5AndDESCBC: // no unit test available
  501. pd.HashName = "MD5";
  502. algorithm = "DES";
  503. break;
  504. case PKCS5.pbeWithMD2AndRC2CBC: // no unit test available
  505. // TODO - RC2-CBC-Parameter (PKCS5)
  506. // if missing default to 32 bits !!!
  507. pd.HashName = "MD2";
  508. algorithm = "RC2";
  509. keyLength = 4; // default
  510. break;
  511. case PKCS5.pbeWithMD5AndRC2CBC: // no unit test available
  512. // TODO - RC2-CBC-Parameter (PKCS5)
  513. // if missing default to 32 bits !!!
  514. pd.HashName = "MD5";
  515. algorithm = "RC2";
  516. keyLength = 4; // default
  517. break;
  518. case PKCS5.pbeWithSHA1AndDESCBC: // no unit test available
  519. pd.HashName = "SHA1";
  520. algorithm = "DES";
  521. break;
  522. case PKCS5.pbeWithSHA1AndRC2CBC: // no unit test available
  523. // TODO - RC2-CBC-Parameter (PKCS5)
  524. // if missing default to 32 bits !!!
  525. pd.HashName = "SHA1";
  526. algorithm = "RC2";
  527. keyLength = 4; // default
  528. break;
  529. case PKCS12.pbeWithSHAAnd128BitRC4: // no unit test available
  530. pd.HashName = "SHA1";
  531. algorithm = "RC4";
  532. keyLength = 16;
  533. ivLength = 0; // N/A
  534. break;
  535. case PKCS12.pbeWithSHAAnd40BitRC4: // no unit test available
  536. pd.HashName = "SHA1";
  537. algorithm = "RC4";
  538. keyLength = 5;
  539. ivLength = 0; // N/A
  540. break;
  541. case PKCS12.pbeWithSHAAnd3KeyTripleDESCBC:
  542. pd.HashName = "SHA1";
  543. algorithm = "TripleDES";
  544. keyLength = 24;
  545. break;
  546. case PKCS12.pbeWithSHAAnd2KeyTripleDESCBC: // no unit test available
  547. pd.HashName = "SHA1";
  548. algorithm = "TripleDES";
  549. keyLength = 16;
  550. break;
  551. case PKCS12.pbeWithSHAAnd128BitRC2CBC: // no unit test available
  552. pd.HashName = "SHA1";
  553. algorithm = "RC2";
  554. keyLength = 16;
  555. break;
  556. case PKCS12.pbeWithSHAAnd40BitRC2CBC:
  557. pd.HashName = "SHA1";
  558. algorithm = "RC2";
  559. keyLength = 5;
  560. break;
  561. default:
  562. throw new NotSupportedException ("unknown oid " + algorithm);
  563. }
  564. SymmetricAlgorithm sa = null;
  565. sa = SymmetricAlgorithm.Create(algorithm);
  566. sa.Key = pd.DeriveKey (keyLength);
  567. // IV required only for block ciphers (not stream ciphers)
  568. if (ivLength > 0) {
  569. sa.IV = pd.DeriveIV (ivLength);
  570. sa.Mode = CipherMode.CBC;
  571. }
  572. return sa;
  573. }
  574. public byte[] Decrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] encryptedData)
  575. {
  576. SymmetricAlgorithm sa = null;
  577. byte[] result = null;
  578. try {
  579. sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount);
  580. ICryptoTransform ct = sa.CreateDecryptor ();
  581. result = ct.TransformFinalBlock (encryptedData, 0, encryptedData.Length);
  582. }
  583. finally {
  584. if (sa != null)
  585. sa.Clear ();
  586. }
  587. return result;
  588. }
  589. public byte[] Decrypt (PKCS7.EncryptedData ed)
  590. {
  591. return Decrypt (ed.EncryptionAlgorithm.ContentType,
  592. ed.EncryptionAlgorithm.Content [0].Value,
  593. ASN1Convert.ToInt32 (ed.EncryptionAlgorithm.Content [1]),
  594. ed.EncryptedContent);
  595. }
  596. public byte[] Encrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] data)
  597. {
  598. byte[] result = null;
  599. using (SymmetricAlgorithm sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount)) {
  600. ICryptoTransform ct = sa.CreateEncryptor ();
  601. result = ct.TransformFinalBlock (data, 0, data.Length);
  602. }
  603. return result;
  604. }
  605. private DSAParameters GetExistingParameters (out bool found)
  606. {
  607. foreach (X509Certificate cert in Certificates) {
  608. // FIXME: that won't work if parts of the parameters are missing
  609. if (cert.KeyAlgorithmParameters != null) {
  610. DSA dsa = cert.DSA;
  611. if (dsa != null) {
  612. found = true;
  613. return dsa.ExportParameters (false);
  614. }
  615. }
  616. }
  617. found = false;
  618. return new DSAParameters ();
  619. }
  620. private void AddPrivateKey (PKCS8.PrivateKeyInfo pki)
  621. {
  622. byte[] privateKey = pki.PrivateKey;
  623. switch (privateKey [0]) {
  624. case 0x02:
  625. bool found;
  626. DSAParameters p = GetExistingParameters (out found);
  627. if (found) {
  628. _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p));
  629. }
  630. break;
  631. case 0x30:
  632. _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey));
  633. break;
  634. default:
  635. Array.Clear (privateKey, 0, privateKey.Length);
  636. throw new CryptographicException ("Unknown private key format");
  637. }
  638. Array.Clear (privateKey, 0, privateKey.Length);
  639. }
  640. private void ReadSafeBag (ASN1 safeBag)
  641. {
  642. if (safeBag.Tag != 0x30)
  643. throw new ArgumentException ("invalid safeBag");
  644. ASN1 bagId = safeBag [0];
  645. if (bagId.Tag != 0x06)
  646. throw new ArgumentException ("invalid safeBag id");
  647. ASN1 bagValue = safeBag [1];
  648. string oid = ASN1Convert.ToOid (bagId);
  649. switch (oid) {
  650. case keyBag:
  651. // NEED UNIT TEST
  652. AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value));
  653. break;
  654. case pkcs8ShroudedKeyBag:
  655. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
  656. byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
  657. AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted));
  658. Array.Clear (decrypted, 0, decrypted.Length);
  659. break;
  660. case certBag:
  661. PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
  662. if (cert.ContentType != x509Certificate)
  663. throw new NotSupportedException ("unsupport certificate type");
  664. X509Certificate x509 = new X509Certificate (cert.Content [0].Value);
  665. _certs.Add (x509);
  666. break;
  667. case crlBag:
  668. // TODO
  669. break;
  670. case secretBag:
  671. byte[] secret = bagValue.Value;
  672. _secretBags.Add(secret);
  673. break;
  674. case safeContentsBag:
  675. // TODO - ? recurse ?
  676. break;
  677. default:
  678. throw new ArgumentException ("unknown safeBag oid");
  679. }
  680. if (safeBag.Count > 2) {
  681. ASN1 bagAttributes = safeBag [2];
  682. if (bagAttributes.Tag != 0x31)
  683. throw new ArgumentException ("invalid safeBag attributes id");
  684. for (int i = 0; i < bagAttributes.Count; i++) {
  685. ASN1 pkcs12Attribute = bagAttributes[i];
  686. if (pkcs12Attribute.Tag != 0x30)
  687. throw new ArgumentException ("invalid PKCS12 attributes id");
  688. ASN1 attrId = pkcs12Attribute [0];
  689. if (attrId.Tag != 0x06)
  690. throw new ArgumentException ("invalid attribute id");
  691. string attrOid = ASN1Convert.ToOid (attrId);
  692. ASN1 attrValues = pkcs12Attribute[1];
  693. for (int j = 0; j < attrValues.Count; j++) {
  694. ASN1 attrValue = attrValues[j];
  695. switch (attrOid) {
  696. case PKCS9.friendlyName:
  697. if (attrValue.Tag != 0x1e)
  698. throw new ArgumentException ("invalid attribute value id");
  699. break;
  700. case PKCS9.localKeyId:
  701. if (attrValue.Tag != 0x04)
  702. throw new ArgumentException ("invalid attribute value id");
  703. break;
  704. default:
  705. // Unknown OID -- don't check Tag
  706. break;
  707. }
  708. }
  709. }
  710. }
  711. _safeBags.Add (new SafeBag(oid, safeBag));
  712. }
  713. private ASN1 Pkcs8ShroudedKeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
  714. {
  715. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
  716. if (aa is RSA) {
  717. pki.Algorithm = "1.2.840.113549.1.1.1";
  718. pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
  719. }
  720. else if (aa is DSA) {
  721. pki.Algorithm = null;
  722. pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
  723. }
  724. else
  725. throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
  726. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo ();
  727. epki.Algorithm = pbeWithSHAAnd3KeyTripleDESCBC;
  728. epki.IterationCount = _iterations;
  729. epki.EncryptedData = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, epki.Salt, _iterations, pki.GetBytes ());
  730. ASN1 safeBag = new ASN1 (0x30);
  731. safeBag.Add (ASN1Convert.FromOid (pkcs8ShroudedKeyBag));
  732. ASN1 bagValue = new ASN1 (0xA0);
  733. bagValue.Add (new ASN1 (epki.GetBytes ()));
  734. safeBag.Add (bagValue);
  735. if (attributes != null) {
  736. ASN1 bagAttributes = new ASN1 (0x31);
  737. IDictionaryEnumerator de = attributes.GetEnumerator ();
  738. while (de.MoveNext ()) {
  739. string oid = (string)de.Key;
  740. switch (oid) {
  741. case PKCS9.friendlyName:
  742. ArrayList names = (ArrayList)de.Value;
  743. if (names.Count > 0) {
  744. ASN1 pkcs12Attribute = new ASN1 (0x30);
  745. pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
  746. ASN1 attrValues = new ASN1 (0x31);
  747. foreach (byte[] name in names) {
  748. ASN1 attrValue = new ASN1 (0x1e);
  749. attrValue.Value = name;
  750. attrValues.Add (attrValue);
  751. }
  752. pkcs12Attribute.Add (attrValues);
  753. bagAttributes.Add (pkcs12Attribute);
  754. }
  755. break;
  756. case PKCS9.localKeyId:
  757. ArrayList keys = (ArrayList)de.Value;
  758. if (keys.Count > 0) {
  759. ASN1 pkcs12Attribute = new ASN1 (0x30);
  760. pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
  761. ASN1 attrValues = new ASN1 (0x31);
  762. foreach (byte[] key in keys) {
  763. ASN1 attrValue = new ASN1 (0x04);
  764. attrValue.Value = key;
  765. attrValues.Add (attrValue);
  766. }
  767. pkcs12Attribute.Add (attrValues);
  768. bagAttributes.Add (pkcs12Attribute);
  769. }
  770. break;
  771. default:
  772. break;
  773. }
  774. }
  775. if (bagAttributes.Count > 0) {
  776. safeBag.Add (bagAttributes);
  777. }
  778. }
  779. return safeBag;
  780. }
  781. private ASN1 KeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes)
  782. {
  783. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo ();
  784. if (aa is RSA) {
  785. pki.Algorithm = "1.2.840.113549.1.1.1";
  786. pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa);
  787. }
  788. else if (aa is DSA) {
  789. pki.Algorithm = null;
  790. pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa);
  791. }
  792. else
  793. throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ());
  794. ASN1 safeBag = new ASN1 (0x30);
  795. safeBag.Add (ASN1Convert.FromOid (keyBag));
  796. ASN1 bagValue = new ASN1 (0xA0);
  797. bagValue.Add (new ASN1 (pki.GetBytes ()));
  798. safeBag.Add (bagValue);
  799. if (attributes != null) {
  800. ASN1 bagAttributes = new ASN1 (0x31);
  801. IDictionaryEnumerator de = attributes.GetEnumerator ();
  802. while (de.MoveNext ()) {
  803. string oid = (string)de.Key;
  804. switch (oid) {
  805. case PKCS9.friendlyName:
  806. ArrayList names = (ArrayList)de.Value;
  807. if (names.Count > 0) {
  808. ASN1 pkcs12Attribute = new ASN1 (0x30);
  809. pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
  810. ASN1 attrValues = new ASN1 (0x31);
  811. foreach (byte[] name in names) {
  812. ASN1 attrValue = new ASN1 (0x1e);
  813. attrValue.Value = name;
  814. attrValues.Add (attrValue);
  815. }
  816. pkcs12Attribute.Add (attrValues);
  817. bagAttributes.Add (pkcs12Attribute);
  818. }
  819. break;
  820. case PKCS9.localKeyId:
  821. ArrayList keys = (ArrayList)de.Value;
  822. if (keys.Count > 0) {
  823. ASN1 pkcs12Attribute = new ASN1 (0x30);
  824. pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
  825. ASN1 attrValues = new ASN1 (0x31);
  826. foreach (byte[] key in keys) {
  827. ASN1 attrValue = new ASN1 (0x04);
  828. attrValue.Value = key;
  829. attrValues.Add (attrValue);
  830. }
  831. pkcs12Attribute.Add (attrValues);
  832. bagAttributes.Add (pkcs12Attribute);
  833. }
  834. break;
  835. default:
  836. break;
  837. }
  838. }
  839. if (bagAttributes.Count > 0) {
  840. safeBag.Add (bagAttributes);
  841. }
  842. }
  843. return safeBag;
  844. }
  845. private ASN1 SecretBagSafeBag (byte[] secret, IDictionary attributes)
  846. {
  847. ASN1 safeBag = new ASN1 (0x30);
  848. safeBag.Add (ASN1Convert.FromOid (secretBag));
  849. ASN1 bagValue = new ASN1 (0x80, secret);
  850. safeBag.Add (bagValue);
  851. if (attributes != null) {
  852. ASN1 bagAttributes = new ASN1 (0x31);
  853. IDictionaryEnumerator de = attributes.GetEnumerator ();
  854. while (de.MoveNext ()) {
  855. string oid = (string)de.Key;
  856. switch (oid) {
  857. case PKCS9.friendlyName:
  858. ArrayList names = (ArrayList)de.Value;
  859. if (names.Count > 0) {
  860. ASN1 pkcs12Attribute = new ASN1 (0x30);
  861. pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName));
  862. ASN1 attrValues = new ASN1 (0x31);
  863. foreach (byte[] name in names) {
  864. ASN1 attrValue = new ASN1 (0x1e);
  865. attrValue.Value = name;
  866. attrValues.Add (attrValue);
  867. }
  868. pkcs12Attribute.Add (attrValues);
  869. bagAttributes.Add (pkcs12Attribute);
  870. }
  871. break;
  872. case PKCS9.localKeyId:
  873. ArrayList keys = (ArrayList)de.Value;
  874. if (keys.Count > 0) {
  875. ASN1 pkcs12Attribute = new ASN1 (0x30);
  876. pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId));
  877. ASN1 attrValues = new ASN1 (0x31);
  878. foreach (byte[] key in keys) {
  879. ASN1 attrValue = new ASN1 (0x04);
  880. attrValue.Value = key;
  881. attrValues.Add (attrValue);
  882. }
  883. pkcs12Attribute.Add (attrValues);
  884. bagAttributes.Add (pkcs12Attribute);
  885. }
  886. break;
  887. default:
  888. break;
  889. }
  890. }
  891. if (bagAttributes.Count > 0) {
  892. safeBag.Add (bagAttributes);
  893. }
  894. }
  895. return safeBag;
  896. }
  897. private ASN1 CertificateSafeBag (X509Certificate x509, IDictionary attributes)
  898. {
  899. ASN1 encapsulatedCertificate = new ASN1 (0x04, x509.RawData);
  900. PKCS7.ContentInfo ci = new PKCS7.ContentInfo ();
  901. ci.ContentType = x509Certificate;
  902. ci.Content.Add (encapsulatedCertificate);
  903. ASN1 bagValue = new ASN1 (0xA0);
  904. bagValue.Add (ci.ASN1);
  905. ASN1 safeBag = new ASN1 (0x30);
  906. safeBag.Add (ASN1Convert.FromOid (certBag));
  907. safeBag.Add (bagValue);
  908. if (attributes != null) {
  909. ASN1 bagAttributes = new ASN1 (0x31);
  910. IDictionaryEnumerator de = attributes.GetEnumerator ();
  911. while (de.MoveNext ()) {
  912. string oid = (string)de.Key;
  913. switch (oid) {
  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);
  924. }
  925. pkcs12Attribute.Add (attrValues);
  926. bagAttributes.Add (pkcs12Attribute);
  927. }
  928. break;
  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);
  939. }
  940. pkcs12Attribute.Add (attrValues);
  941. bagAttributes.Add (pkcs12Attribute);
  942. }
  943. break;
  944. default:
  945. break;
  946. }
  947. }
  948. if (bagAttributes.Count > 0) {
  949. safeBag.Add (bagAttributes);
  950. }
  951. }
  952. return safeBag;
  953. }
  954. private byte[] MAC (byte[] password, byte[] salt, int iterations, byte[] data)
  955. {
  956. PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes ();
  957. pd.HashName = "SHA1";
  958. pd.Password = password;
  959. pd.Salt = salt;
  960. pd.IterationCount = iterations;
  961. HMACSHA1 hmac = (HMACSHA1) HMACSHA1.Create ();
  962. hmac.Key = pd.DeriveMAC (20);
  963. return hmac.ComputeHash (data, 0, data.Length);
  964. }
  965. /*
  966. * SafeContents ::= SEQUENCE OF SafeBag
  967. *
  968. * SafeBag ::= SEQUENCE {
  969. * bagId BAG-TYPE.&id ({PKCS12BagSet}),
  970. * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
  971. * bagAttributes SET OF PKCS12Attribute OPTIONAL
  972. * }
  973. */
  974. public byte[] GetBytes ()
  975. {
  976. // TODO (incomplete)
  977. ASN1 safeBagSequence = new ASN1 (0x30);
  978. // Sync Safe Bag list since X509CertificateCollection may be updated
  979. ArrayList scs = new ArrayList ();
  980. foreach (SafeBag sb in _safeBags) {
  981. if (sb.BagOID.Equals (certBag)) {
  982. ASN1 safeBag = sb.ASN1;
  983. ASN1 bagValue = safeBag [1];
  984. PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value);
  985. scs.Add (new X509Certificate (cert.Content [0].Value));
  986. }
  987. }
  988. ArrayList addcerts = new ArrayList ();
  989. ArrayList removecerts = new ArrayList ();
  990. foreach (X509Certificate c in Certificates) {
  991. bool found = false;
  992. foreach (X509Certificate lc in scs) {
  993. if (Compare (c.RawData, lc.RawData)) {
  994. found = true;
  995. }
  996. }
  997. if (!found) {
  998. addcerts.Add (c);
  999. }
  1000. }
  1001. foreach (X509Certificate c in scs) {
  1002. bool found = false;
  1003. foreach (X509Certificate lc in Certificates) {
  1004. if (Compare (c.RawData, lc.RawData)) {
  1005. found = true;
  1006. }
  1007. }
  1008. if (!found) {
  1009. removecerts.Add (c);
  1010. }
  1011. }
  1012. foreach (X509Certificate c in removecerts) {
  1013. RemoveCertificate (c);
  1014. }
  1015. foreach (X509Certificate c in addcerts) {
  1016. AddCertificate (c);
  1017. }
  1018. // Sync done
  1019. if (_safeBags.Count > 0) {
  1020. ASN1 certsSafeBag = new ASN1 (0x30);
  1021. foreach (SafeBag sb in _safeBags) {
  1022. if (sb.BagOID.Equals (certBag)) {
  1023. certsSafeBag.Add (sb.ASN1);
  1024. }
  1025. }
  1026. if (certsSafeBag.Count > 0) {
  1027. PKCS7.ContentInfo contentInfo = EncryptedContentInfo (certsSafeBag, pbeWithSHAAnd3KeyTripleDESCBC);
  1028. safeBagSequence.Add (contentInfo.ASN1);
  1029. }
  1030. }
  1031. if (_safeBags.Count > 0) {
  1032. ASN1 safeContents = new ASN1 (0x30);
  1033. foreach (SafeBag sb in _safeBags) {
  1034. if (sb.BagOID.Equals (keyBag) ||
  1035. sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1036. safeContents.Add (sb.ASN1);
  1037. }
  1038. }
  1039. if (safeContents.Count > 0) {
  1040. ASN1 content = new ASN1 (0xA0);
  1041. content.Add (new ASN1 (0x04, safeContents.GetBytes ()));
  1042. PKCS7.ContentInfo keyBag = new PKCS7.ContentInfo (PKCS7.Oid.data);
  1043. keyBag.Content = content;
  1044. safeBagSequence.Add (keyBag.ASN1);
  1045. }
  1046. }
  1047. // Doing SecretBags separately in case we want to change their encryption independently.
  1048. if (_safeBags.Count > 0) {
  1049. ASN1 secretsSafeBag = new ASN1 (0x30);
  1050. foreach (SafeBag sb in _safeBags) {
  1051. if (sb.BagOID.Equals (secretBag)) {
  1052. secretsSafeBag.Add (sb.ASN1);
  1053. }
  1054. }
  1055. if (secretsSafeBag.Count > 0) {
  1056. PKCS7.ContentInfo contentInfo = EncryptedContentInfo (secretsSafeBag, pbeWithSHAAnd3KeyTripleDESCBC);
  1057. safeBagSequence.Add (contentInfo.ASN1);
  1058. }
  1059. }
  1060. ASN1 encapsulates = new ASN1 (0x04, safeBagSequence.GetBytes ());
  1061. ASN1 ci = new ASN1 (0xA0);
  1062. ci.Add (encapsulates);
  1063. PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (PKCS7.Oid.data);
  1064. authSafe.Content = ci;
  1065. ASN1 macData = new ASN1 (0x30);
  1066. if (_password != null) {
  1067. // only for password based encryption
  1068. byte[] salt = new byte [20];
  1069. RNG.GetBytes (salt);
  1070. byte[] macValue = MAC (_password, salt, _iterations, authSafe.Content [0].Value);
  1071. ASN1 oidSeq = new ASN1 (0x30);
  1072. oidSeq.Add (ASN1Convert.FromOid ("1.3.14.3.2.26")); // SHA1
  1073. oidSeq.Add (new ASN1 (0x05));
  1074. ASN1 mac = new ASN1 (0x30);
  1075. mac.Add (oidSeq);
  1076. mac.Add (new ASN1 (0x04, macValue));
  1077. macData.Add (mac);
  1078. macData.Add (new ASN1 (0x04, salt));
  1079. macData.Add (ASN1Convert.FromInt32 (_iterations));
  1080. }
  1081. ASN1 version = new ASN1 (0x02, new byte [1] { 0x03 });
  1082. ASN1 pfx = new ASN1 (0x30);
  1083. pfx.Add (version);
  1084. pfx.Add (authSafe.ASN1);
  1085. if (macData.Count > 0) {
  1086. // only for password based encryption
  1087. pfx.Add (macData);
  1088. }
  1089. return pfx.GetBytes ();
  1090. }
  1091. // Creates an encrypted PKCS#7 ContentInfo with safeBags as its SafeContents. Used in GetBytes(), above.
  1092. private PKCS7.ContentInfo EncryptedContentInfo(ASN1 safeBags, string algorithmOid)
  1093. {
  1094. byte[] salt = new byte [8];
  1095. RNG.GetBytes (salt);
  1096. ASN1 seqParams = new ASN1 (0x30);
  1097. seqParams.Add (new ASN1 (0x04, salt));
  1098. seqParams.Add (ASN1Convert.FromInt32 (_iterations));
  1099. ASN1 seqPbe = new ASN1 (0x30);
  1100. seqPbe.Add (ASN1Convert.FromOid (algorithmOid));
  1101. seqPbe.Add (seqParams);
  1102. byte[] encrypted = Encrypt (algorithmOid, salt, _iterations, safeBags.GetBytes ());
  1103. ASN1 encryptedContent = new ASN1 (0x80, encrypted);
  1104. ASN1 seq = new ASN1 (0x30);
  1105. seq.Add (ASN1Convert.FromOid (PKCS7.Oid.data));
  1106. seq.Add (seqPbe);
  1107. seq.Add (encryptedContent);
  1108. ASN1 version = new ASN1 (0x02, new byte [1] { 0x00 });
  1109. ASN1 encData = new ASN1 (0x30);
  1110. encData.Add (version);
  1111. encData.Add (seq);
  1112. ASN1 finalContent = new ASN1 (0xA0);
  1113. finalContent.Add (encData);
  1114. PKCS7.ContentInfo bag = new PKCS7.ContentInfo (PKCS7.Oid.encryptedData);
  1115. bag.Content = finalContent;
  1116. return bag;
  1117. }
  1118. public void AddCertificate (X509Certificate cert)
  1119. {
  1120. AddCertificate (cert, null);
  1121. }
  1122. public void AddCertificate (X509Certificate cert, IDictionary attributes)
  1123. {
  1124. bool found = false;
  1125. for (int i = 0; !found && i < _safeBags.Count; i++) {
  1126. SafeBag sb = (SafeBag)_safeBags [i];
  1127. if (sb.BagOID.Equals (certBag)) {
  1128. ASN1 safeBag = sb.ASN1;
  1129. ASN1 bagValue = safeBag [1];
  1130. PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
  1131. X509Certificate c = new X509Certificate (crt.Content [0].Value);
  1132. if (Compare (cert.RawData, c.RawData)) {
  1133. found = true;
  1134. }
  1135. }
  1136. }
  1137. if (!found) {
  1138. _safeBags.Add (new SafeBag (certBag, CertificateSafeBag (cert, attributes)));
  1139. _certsChanged = true;
  1140. }
  1141. }
  1142. public void RemoveCertificate (X509Certificate cert)
  1143. {
  1144. RemoveCertificate (cert, null);
  1145. }
  1146. public void RemoveCertificate (X509Certificate cert, IDictionary attrs)
  1147. {
  1148. int certIndex = -1;
  1149. for (int i = 0; certIndex == -1 && i < _safeBags.Count; i++) {
  1150. SafeBag sb = (SafeBag)_safeBags [i];
  1151. if (sb.BagOID.Equals (certBag)) {
  1152. ASN1 safeBag = sb.ASN1;
  1153. ASN1 bagValue = safeBag [1];
  1154. PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
  1155. X509Certificate c = new X509Certificate (crt.Content [0].Value);
  1156. if (Compare (cert.RawData, c.RawData)) {
  1157. if (attrs != null) {
  1158. if (safeBag.Count == 3) {
  1159. ASN1 bagAttributes = safeBag [2];
  1160. int bagAttributesFound = 0;
  1161. for (int j = 0; j < bagAttributes.Count; j++) {
  1162. ASN1 pkcs12Attribute = bagAttributes [j];
  1163. ASN1 attrId = pkcs12Attribute [0];
  1164. string ao = ASN1Convert.ToOid (attrId);
  1165. ArrayList dattrValues = (ArrayList)attrs [ao];
  1166. if (dattrValues != null) {
  1167. ASN1 attrValues = pkcs12Attribute [1];
  1168. if (dattrValues.Count == attrValues.Count) {
  1169. int attrValuesFound = 0;
  1170. for (int k = 0; k < attrValues.Count; k++) {
  1171. ASN1 attrValue = attrValues [k];
  1172. byte[] value = (byte[])dattrValues [k];
  1173. if (Compare (value, attrValue.Value)) {
  1174. attrValuesFound += 1;
  1175. }
  1176. }
  1177. if (attrValuesFound == attrValues.Count) {
  1178. bagAttributesFound += 1;
  1179. }
  1180. }
  1181. }
  1182. }
  1183. if (bagAttributesFound == bagAttributes.Count) {
  1184. certIndex = i;
  1185. }
  1186. }
  1187. } else {
  1188. certIndex = i;
  1189. }
  1190. }
  1191. }
  1192. }
  1193. if (certIndex != -1) {
  1194. _safeBags.RemoveAt (certIndex);
  1195. _certsChanged = true;
  1196. }
  1197. }
  1198. private bool CompareAsymmetricAlgorithm (AsymmetricAlgorithm a1, AsymmetricAlgorithm a2)
  1199. {
  1200. // fast path
  1201. if (a1.KeySize != a2.KeySize)
  1202. return false;
  1203. // compare public keys - if they match we can assume the private match too
  1204. return (a1.ToXmlString (false) == a2.ToXmlString (false));
  1205. }
  1206. public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
  1207. {
  1208. AddPkcs8ShroudedKeyBag (aa, null);
  1209. }
  1210. public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
  1211. {
  1212. bool found = false;
  1213. for (int i = 0; !found && i < _safeBags.Count; i++) {
  1214. SafeBag sb = (SafeBag)_safeBags [i];
  1215. if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1216. ASN1 bagValue = sb.ASN1 [1];
  1217. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
  1218. byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
  1219. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
  1220. byte[] privateKey = pki.PrivateKey;
  1221. AsymmetricAlgorithm saa = null;
  1222. switch (privateKey [0]) {
  1223. case 0x02:
  1224. DSAParameters p = new DSAParameters (); // FIXME
  1225. saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1226. break;
  1227. case 0x30:
  1228. saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1229. break;
  1230. default:
  1231. Array.Clear (decrypted, 0, decrypted.Length);
  1232. Array.Clear (privateKey, 0, privateKey.Length);
  1233. throw new CryptographicException ("Unknown private key format");
  1234. }
  1235. Array.Clear (decrypted, 0, decrypted.Length);
  1236. Array.Clear (privateKey, 0, privateKey.Length);
  1237. if (CompareAsymmetricAlgorithm (aa , saa)) {
  1238. found = true;
  1239. }
  1240. }
  1241. }
  1242. if (!found) {
  1243. _safeBags.Add (new SafeBag (pkcs8ShroudedKeyBag, Pkcs8ShroudedKeyBagSafeBag (aa, attributes)));
  1244. _keyBagsChanged = true;
  1245. }
  1246. }
  1247. public void RemovePkcs8ShroudedKeyBag (AsymmetricAlgorithm aa)
  1248. {
  1249. int aaIndex = -1;
  1250. for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
  1251. SafeBag sb = (SafeBag)_safeBags [i];
  1252. if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1253. ASN1 bagValue = sb.ASN1 [1];
  1254. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
  1255. byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
  1256. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
  1257. byte[] privateKey = pki.PrivateKey;
  1258. AsymmetricAlgorithm saa = null;
  1259. switch (privateKey [0]) {
  1260. case 0x02:
  1261. DSAParameters p = new DSAParameters (); // FIXME
  1262. saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1263. break;
  1264. case 0x30:
  1265. saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1266. break;
  1267. default:
  1268. Array.Clear (decrypted, 0, decrypted.Length);
  1269. Array.Clear (privateKey, 0, privateKey.Length);
  1270. throw new CryptographicException ("Unknown private key format");
  1271. }
  1272. Array.Clear (decrypted, 0, decrypted.Length);
  1273. Array.Clear (privateKey, 0, privateKey.Length);
  1274. if (CompareAsymmetricAlgorithm (aa, saa)) {
  1275. aaIndex = i;
  1276. }
  1277. }
  1278. }
  1279. if (aaIndex != -1) {
  1280. _safeBags.RemoveAt (aaIndex);
  1281. _keyBagsChanged = true;
  1282. }
  1283. }
  1284. public void AddKeyBag (AsymmetricAlgorithm aa)
  1285. {
  1286. AddKeyBag (aa, null);
  1287. }
  1288. public void AddKeyBag (AsymmetricAlgorithm aa, IDictionary attributes)
  1289. {
  1290. bool found = false;
  1291. for (int i = 0; !found && i < _safeBags.Count; i++) {
  1292. SafeBag sb = (SafeBag)_safeBags [i];
  1293. if (sb.BagOID.Equals (keyBag)) {
  1294. ASN1 bagValue = sb.ASN1 [1];
  1295. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
  1296. byte[] privateKey = pki.PrivateKey;
  1297. AsymmetricAlgorithm saa = null;
  1298. switch (privateKey [0]) {
  1299. case 0x02:
  1300. DSAParameters p = new DSAParameters (); // FIXME
  1301. saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1302. break;
  1303. case 0x30:
  1304. saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1305. break;
  1306. default:
  1307. Array.Clear (privateKey, 0, privateKey.Length);
  1308. throw new CryptographicException ("Unknown private key format");
  1309. }
  1310. Array.Clear (privateKey, 0, privateKey.Length);
  1311. if (CompareAsymmetricAlgorithm (aa, saa)) {
  1312. found = true;
  1313. }
  1314. }
  1315. }
  1316. if (!found) {
  1317. _safeBags.Add (new SafeBag (keyBag, KeyBagSafeBag (aa, attributes)));
  1318. _keyBagsChanged = true;
  1319. }
  1320. }
  1321. public void RemoveKeyBag (AsymmetricAlgorithm aa)
  1322. {
  1323. int aaIndex = -1;
  1324. for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) {
  1325. SafeBag sb = (SafeBag)_safeBags [i];
  1326. if (sb.BagOID.Equals (keyBag)) {
  1327. ASN1 bagValue = sb.ASN1 [1];
  1328. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
  1329. byte[] privateKey = pki.PrivateKey;
  1330. AsymmetricAlgorithm saa = null;
  1331. switch (privateKey [0]) {
  1332. case 0x02:
  1333. DSAParameters p = new DSAParameters (); // FIXME
  1334. saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1335. break;
  1336. case 0x30:
  1337. saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1338. break;
  1339. default:
  1340. Array.Clear (privateKey, 0, privateKey.Length);
  1341. throw new CryptographicException ("Unknown private key format");
  1342. }
  1343. Array.Clear (privateKey, 0, privateKey.Length);
  1344. if (CompareAsymmetricAlgorithm (aa, saa)) {
  1345. aaIndex = i;
  1346. }
  1347. }
  1348. }
  1349. if (aaIndex != -1) {
  1350. _safeBags.RemoveAt (aaIndex);
  1351. _keyBagsChanged = true;
  1352. }
  1353. }
  1354. public void AddSecretBag (byte[] secret)
  1355. {
  1356. AddSecretBag (secret, null);
  1357. }
  1358. public void AddSecretBag (byte[] secret, IDictionary attributes)
  1359. {
  1360. bool found = false;
  1361. for (int i = 0; !found && i < _safeBags.Count; i++) {
  1362. SafeBag sb = (SafeBag)_safeBags [i];
  1363. if (sb.BagOID.Equals (secretBag)) {
  1364. ASN1 bagValue = sb.ASN1 [1];
  1365. byte[] ssecret = bagValue.Value;
  1366. if (Compare (secret, ssecret)) {
  1367. found = true;
  1368. }
  1369. }
  1370. }
  1371. if (!found) {
  1372. _safeBags.Add (new SafeBag (secretBag, SecretBagSafeBag (secret, attributes)));
  1373. _secretBagsChanged = true;
  1374. }
  1375. }
  1376. public void RemoveSecretBag (byte[] secret)
  1377. {
  1378. int sIndex = -1;
  1379. for (int i = 0; sIndex == -1 && i < _safeBags.Count; i++) {
  1380. SafeBag sb = (SafeBag)_safeBags [i];
  1381. if (sb.BagOID.Equals (secretBag)) {
  1382. ASN1 bagValue = sb.ASN1 [1];
  1383. byte[] ssecret = bagValue.Value;
  1384. if (Compare (secret, ssecret)) {
  1385. sIndex = i;
  1386. }
  1387. }
  1388. }
  1389. if (sIndex != -1) {
  1390. _safeBags.RemoveAt (sIndex);
  1391. _secretBagsChanged = true;
  1392. }
  1393. }
  1394. public AsymmetricAlgorithm GetAsymmetricAlgorithm (IDictionary attrs)
  1395. {
  1396. foreach (SafeBag sb in _safeBags) {
  1397. if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1398. ASN1 safeBag = sb.ASN1;
  1399. if (safeBag.Count == 3) {
  1400. ASN1 bagAttributes = safeBag [2];
  1401. int bagAttributesFound = 0;
  1402. for (int i = 0; i < bagAttributes.Count; i++) {
  1403. ASN1 pkcs12Attribute = bagAttributes [i];
  1404. ASN1 attrId = pkcs12Attribute [0];
  1405. string ao = ASN1Convert.ToOid (attrId);
  1406. ArrayList dattrValues = (ArrayList)attrs [ao];
  1407. if (dattrValues != null) {
  1408. ASN1 attrValues = pkcs12Attribute [1];
  1409. if (dattrValues.Count == attrValues.Count) {
  1410. int attrValuesFound = 0;
  1411. for (int j = 0; j < attrValues.Count; j++) {
  1412. ASN1 attrValue = attrValues [j];
  1413. byte[] value = (byte[])dattrValues [j];
  1414. if (Compare (value, attrValue.Value)) {
  1415. attrValuesFound += 1;
  1416. }
  1417. }
  1418. if (attrValuesFound == attrValues.Count) {
  1419. bagAttributesFound += 1;
  1420. }
  1421. }
  1422. }
  1423. }
  1424. if (bagAttributesFound == bagAttributes.Count) {
  1425. ASN1 bagValue = safeBag [1];
  1426. AsymmetricAlgorithm aa = null;
  1427. if (sb.BagOID.Equals (keyBag)) {
  1428. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
  1429. byte[] privateKey = pki.PrivateKey;
  1430. switch (privateKey [0]) {
  1431. case 0x02:
  1432. DSAParameters p = new DSAParameters (); // FIXME
  1433. aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1434. break;
  1435. case 0x30:
  1436. aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1437. break;
  1438. default:
  1439. break;
  1440. }
  1441. Array.Clear (privateKey, 0, privateKey.Length);
  1442. } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1443. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
  1444. byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
  1445. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
  1446. byte[] privateKey = pki.PrivateKey;
  1447. switch (privateKey [0]) {
  1448. case 0x02:
  1449. DSAParameters p = new DSAParameters (); // FIXME
  1450. aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1451. break;
  1452. case 0x30:
  1453. aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1454. break;
  1455. default:
  1456. break;
  1457. }
  1458. Array.Clear (privateKey, 0, privateKey.Length);
  1459. Array.Clear (decrypted, 0, decrypted.Length);
  1460. }
  1461. return aa;
  1462. }
  1463. }
  1464. }
  1465. }
  1466. return null;
  1467. }
  1468. public byte[] GetSecret (IDictionary attrs)
  1469. {
  1470. foreach (SafeBag sb in _safeBags) {
  1471. if (sb.BagOID.Equals (secretBag)) {
  1472. ASN1 safeBag = sb.ASN1;
  1473. if (safeBag.Count == 3) {
  1474. ASN1 bagAttributes = safeBag [2];
  1475. int bagAttributesFound = 0;
  1476. for (int i = 0; i < bagAttributes.Count; i++) {
  1477. ASN1 pkcs12Attribute = bagAttributes [i];
  1478. ASN1 attrId = pkcs12Attribute [0];
  1479. string ao = ASN1Convert.ToOid (attrId);
  1480. ArrayList dattrValues = (ArrayList)attrs [ao];
  1481. if (dattrValues != null) {
  1482. ASN1 attrValues = pkcs12Attribute [1];
  1483. if (dattrValues.Count == attrValues.Count) {
  1484. int attrValuesFound = 0;
  1485. for (int j = 0; j < attrValues.Count; j++) {
  1486. ASN1 attrValue = attrValues [j];
  1487. byte[] value = (byte[])dattrValues [j];
  1488. if (Compare (value, attrValue.Value)) {
  1489. attrValuesFound += 1;
  1490. }
  1491. }
  1492. if (attrValuesFound == attrValues.Count) {
  1493. bagAttributesFound += 1;
  1494. }
  1495. }
  1496. }
  1497. }
  1498. if (bagAttributesFound == bagAttributes.Count) {
  1499. ASN1 bagValue = safeBag [1];
  1500. return bagValue.Value;
  1501. }
  1502. }
  1503. }
  1504. }
  1505. return null;
  1506. }
  1507. public X509Certificate GetCertificate (IDictionary attrs)
  1508. {
  1509. foreach (SafeBag sb in _safeBags) {
  1510. if (sb.BagOID.Equals (certBag)) {
  1511. ASN1 safeBag = sb.ASN1;
  1512. if (safeBag.Count == 3) {
  1513. ASN1 bagAttributes = safeBag [2];
  1514. int bagAttributesFound = 0;
  1515. for (int i = 0; i < bagAttributes.Count; i++) {
  1516. ASN1 pkcs12Attribute = bagAttributes [i];
  1517. ASN1 attrId = pkcs12Attribute [0];
  1518. string ao = ASN1Convert.ToOid (attrId);
  1519. ArrayList dattrValues = (ArrayList)attrs [ao];
  1520. if (dattrValues != null) {
  1521. ASN1 attrValues = pkcs12Attribute [1];
  1522. if (dattrValues.Count == attrValues.Count) {
  1523. int attrValuesFound = 0;
  1524. for (int j = 0; j < attrValues.Count; j++) {
  1525. ASN1 attrValue = attrValues [j];
  1526. byte[] value = (byte[])dattrValues [j];
  1527. if (Compare (value, attrValue.Value)) {
  1528. attrValuesFound += 1;
  1529. }
  1530. }
  1531. if (attrValuesFound == attrValues.Count) {
  1532. bagAttributesFound += 1;
  1533. }
  1534. }
  1535. }
  1536. }
  1537. if (bagAttributesFound == bagAttributes.Count) {
  1538. ASN1 bagValue = safeBag [1];
  1539. PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
  1540. return new X509Certificate (crt.Content [0].Value);
  1541. }
  1542. }
  1543. }
  1544. }
  1545. return null;
  1546. }
  1547. public IDictionary GetAttributes (AsymmetricAlgorithm aa)
  1548. {
  1549. IDictionary result = new Hashtable ();
  1550. foreach (SafeBag sb in _safeBags) {
  1551. if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1552. ASN1 safeBag = sb.ASN1;
  1553. ASN1 bagValue = safeBag [1];
  1554. AsymmetricAlgorithm saa = null;
  1555. if (sb.BagOID.Equals (keyBag)) {
  1556. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value);
  1557. byte[] privateKey = pki.PrivateKey;
  1558. switch (privateKey [0]) {
  1559. case 0x02:
  1560. DSAParameters p = new DSAParameters (); // FIXME
  1561. saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1562. break;
  1563. case 0x30:
  1564. saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1565. break;
  1566. default:
  1567. break;
  1568. }
  1569. Array.Clear (privateKey, 0, privateKey.Length);
  1570. } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) {
  1571. PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value);
  1572. byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData);
  1573. PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted);
  1574. byte[] privateKey = pki.PrivateKey;
  1575. switch (privateKey [0]) {
  1576. case 0x02:
  1577. DSAParameters p = new DSAParameters (); // FIXME
  1578. saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p);
  1579. break;
  1580. case 0x30:
  1581. saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey);
  1582. break;
  1583. default:
  1584. break;
  1585. }
  1586. Array.Clear (privateKey, 0, privateKey.Length);
  1587. Array.Clear (decrypted, 0, decrypted.Length);
  1588. }
  1589. if (saa != null && CompareAsymmetricAlgorithm (saa, aa)) {
  1590. if (safeBag.Count == 3) {
  1591. ASN1 bagAttributes = safeBag [2];
  1592. for (int i = 0; i < bagAttributes.Count; i++) {
  1593. ASN1 pkcs12Attribute = bagAttributes [i];
  1594. ASN1 attrId = pkcs12Attribute [0];
  1595. string aOid = ASN1Convert.ToOid (attrId);
  1596. ArrayList aValues = new ArrayList ();
  1597. ASN1 attrValues = pkcs12Attribute [1];
  1598. for (int j = 0; j < attrValues.Count; j++) {
  1599. ASN1 attrValue = attrValues [j];
  1600. aValues.Add (attrValue.Value);
  1601. }
  1602. result.Add (aOid, aValues);
  1603. }
  1604. }
  1605. }
  1606. }
  1607. }
  1608. return result;
  1609. }
  1610. public IDictionary GetAttributes (X509Certificate cert)
  1611. {
  1612. IDictionary result = new Hashtable ();
  1613. foreach (SafeBag sb in _safeBags) {
  1614. if (sb.BagOID.Equals (certBag)) {
  1615. ASN1 safeBag = sb.ASN1;
  1616. ASN1 bagValue = safeBag [1];
  1617. PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value);
  1618. X509Certificate xc = new X509Certificate (crt.Content [0].Value);
  1619. if (Compare (cert.RawData, xc.RawData)) {
  1620. if (safeBag.Count == 3) {
  1621. ASN1 bagAttributes = safeBag [2];
  1622. for (int i = 0; i < bagAttributes.Count; i++) {
  1623. ASN1 pkcs12Attribute = bagAttributes [i];
  1624. ASN1 attrId = pkcs12Attribute [0];
  1625. string aOid = ASN1Convert.ToOid (attrId);
  1626. ArrayList aValues = new ArrayList ();
  1627. ASN1 attrValues = pkcs12Attribute [1];
  1628. for (int j = 0; j < attrValues.Count; j++) {
  1629. ASN1 attrValue = attrValues [j];
  1630. aValues.Add (attrValue.Value);
  1631. }
  1632. result.Add (aOid, aValues);
  1633. }
  1634. }
  1635. }
  1636. }
  1637. }
  1638. return result;
  1639. }
  1640. public void SaveToFile (string filename)
  1641. {
  1642. if (filename == null)
  1643. throw new ArgumentNullException ("filename");
  1644. using (FileStream fs = File.Create (filename)) {
  1645. byte[] data = GetBytes ();
  1646. fs.Write (data, 0, data.Length);
  1647. }
  1648. }
  1649. public object Clone ()
  1650. {
  1651. PKCS12 clone = null;
  1652. if (_password != null) {
  1653. clone = new PKCS12 (GetBytes (), Encoding.BigEndianUnicode.GetString (_password));
  1654. } else {
  1655. clone = new PKCS12 (GetBytes ());
  1656. }
  1657. clone.IterationCount = this.IterationCount;
  1658. return clone;
  1659. }
  1660. // static
  1661. public const int CryptoApiPasswordLimit = 32;
  1662. static private int password_max_length = Int32.MaxValue;
  1663. // static properties
  1664. // MS CryptoAPI limits the password to a maximum of 31 characters
  1665. // other implementations, like OpenSSL, have no such limitation.
  1666. // Setting a maximum value will truncate the password length to
  1667. // ensure compatibility with MS's PFXImportCertStore API.
  1668. static public int MaximumPasswordLength {
  1669. get { return password_max_length; }
  1670. set {
  1671. if (value < CryptoApiPasswordLimit) {
  1672. string msg = string.Format ("Maximum password length cannot be less than {0}.", CryptoApiPasswordLimit);
  1673. throw new ArgumentOutOfRangeException (msg);
  1674. }
  1675. password_max_length = value;
  1676. }
  1677. }
  1678. }
  1679. }