PKCS12.cs 55 KB

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