PKCS12.cs 56 KB

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