PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/referencesource/System/security/system/security/cryptography/x509/x509extension.cs

https://github.com/pruiz/mono
C# | 738 lines | 588 code | 114 blank | 36 comment | 89 complexity | 2f4cadfdabe0025d0f2d63305676870c MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. // ==++==
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // ==--==
  6. //
  7. // X509Extension.cs
  8. //
  9. namespace System.Security.Cryptography.X509Certificates {
  10. using System.Collections;
  11. using System.Globalization;
  12. using System.Runtime.InteropServices;
  13. using System.Security.Cryptography;
  14. using System.Text;
  15. public class X509Extension : AsnEncodedData {
  16. private bool m_critical = false;
  17. internal X509Extension(string oid) : base (new Oid(oid, OidGroup.ExtensionOrAttribute, false)) {}
  18. #if FEATURE_CORESYSTEM
  19. [SecuritySafeCritical]
  20. #endif
  21. internal X509Extension(IntPtr pExtension) {
  22. CAPI.CERT_EXTENSION extension = (CAPI.CERT_EXTENSION) Marshal.PtrToStructure(pExtension, typeof(CAPI.CERT_EXTENSION));
  23. m_critical = extension.fCritical;
  24. string oidValue = extension.pszObjId;
  25. m_oid = new Oid(oidValue, OidGroup.ExtensionOrAttribute, false);
  26. byte[] rawData = new byte[extension.Value.cbData];
  27. if (extension.Value.pbData != IntPtr.Zero)
  28. Marshal.Copy(extension.Value.pbData, rawData, 0, rawData.Length);
  29. m_rawData = rawData;
  30. }
  31. protected X509Extension() : base () {}
  32. public X509Extension (string oid, byte[] rawData, bool critical) : this (new Oid(oid, OidGroup.ExtensionOrAttribute, true), rawData, critical) {}
  33. public X509Extension (AsnEncodedData encodedExtension, bool critical) : this (encodedExtension.Oid, encodedExtension.RawData, critical) {}
  34. public X509Extension (Oid oid, byte[] rawData, bool critical) : base (oid, rawData) {
  35. if (base.Oid == null || base.Oid.Value == null)
  36. throw new ArgumentNullException("oid");
  37. if (base.Oid.Value.Length == 0)
  38. throw new ArgumentException(SR.GetString(SR.Arg_EmptyOrNullString), "oid.Value");
  39. m_critical = critical;
  40. }
  41. public bool Critical {
  42. get {
  43. return m_critical;
  44. }
  45. set {
  46. m_critical = value;
  47. }
  48. }
  49. public override void CopyFrom (AsnEncodedData asnEncodedData) {
  50. if (asnEncodedData == null)
  51. {
  52. throw new ArgumentNullException("asnEncodedData");
  53. }
  54. X509Extension extension = asnEncodedData as X509Extension;
  55. if (extension == null)
  56. throw new ArgumentException(SR.GetString(SR.Cryptography_X509_ExtensionMismatch));
  57. base.CopyFrom(asnEncodedData);
  58. m_critical = extension.Critical;
  59. }
  60. }
  61. //
  62. // Key Usage flags map the definition in wincrypt.h, so that no mapping will be necessary.
  63. //
  64. [Flags]
  65. public enum X509KeyUsageFlags {
  66. None = 0x0000,
  67. EncipherOnly = 0x0001,
  68. CrlSign = 0x0002,
  69. KeyCertSign = 0x0004,
  70. KeyAgreement = 0x0008,
  71. DataEncipherment = 0x0010,
  72. KeyEncipherment = 0x0020,
  73. NonRepudiation = 0x0040,
  74. DigitalSignature = 0x0080,
  75. DecipherOnly = 0x8000
  76. }
  77. public sealed class X509KeyUsageExtension : X509Extension {
  78. private uint m_keyUsages = 0;
  79. private bool m_decoded = false;
  80. public X509KeyUsageExtension() : base (CAPI.szOID_KEY_USAGE) {
  81. m_decoded = true;
  82. }
  83. #if FEATURE_CORESYSTEM
  84. [SecuritySafeCritical]
  85. #endif
  86. public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical) :
  87. base (CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical) {}
  88. public X509KeyUsageExtension (AsnEncodedData encodedKeyUsage, bool critical) :
  89. base (CAPI.szOID_KEY_USAGE, encodedKeyUsage.RawData, critical) {}
  90. public X509KeyUsageFlags KeyUsages {
  91. get {
  92. if (!m_decoded)
  93. DecodeExtension();
  94. return (X509KeyUsageFlags) m_keyUsages;
  95. }
  96. }
  97. public override void CopyFrom (AsnEncodedData asnEncodedData) {
  98. base.CopyFrom(asnEncodedData);
  99. m_decoded = false;
  100. }
  101. #if FEATURE_CORESYSTEM
  102. [SecuritySafeCritical]
  103. #endif
  104. private void DecodeExtension () {
  105. uint cbDecoded = 0;
  106. SafeLocalAllocHandle decoded = null;
  107. bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_KEY_USAGE),
  108. m_rawData,
  109. out decoded,
  110. out cbDecoded);
  111. if (result == false)
  112. throw new CryptographicException(Marshal.GetLastWin32Error());
  113. CAPI.CRYPTOAPI_BLOB pKeyUsage = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
  114. if (pKeyUsage.cbData > 4)
  115. pKeyUsage.cbData = 4;
  116. byte[] keyUsage = new byte[4];
  117. if (pKeyUsage.pbData != IntPtr.Zero)
  118. Marshal.Copy(pKeyUsage.pbData, keyUsage, 0, (int) pKeyUsage.cbData);
  119. m_keyUsages = BitConverter.ToUInt32(keyUsage, 0);
  120. m_decoded = true;
  121. decoded.Dispose();
  122. }
  123. #if FEATURE_CORESYSTEM
  124. [SecuritySafeCritical]
  125. #endif
  126. private static unsafe byte[] EncodeExtension (X509KeyUsageFlags keyUsages) {
  127. CAPI.CRYPT_BIT_BLOB blob = new CAPI.CRYPT_BIT_BLOB();
  128. blob.cbData = 2;
  129. blob.pbData = new IntPtr(&keyUsages);
  130. blob.cUnusedBits = 0;
  131. byte[] encodedKeyUsages = null;
  132. if (!CAPI.EncodeObject(CAPI.szOID_KEY_USAGE, new IntPtr(&blob), out encodedKeyUsages))
  133. throw new CryptographicException(Marshal.GetLastWin32Error());
  134. return encodedKeyUsages;
  135. }
  136. }
  137. public sealed class X509BasicConstraintsExtension : X509Extension {
  138. private bool m_isCA = false;
  139. private bool m_hasPathLenConstraint = false;
  140. private int m_pathLenConstraint = 0;
  141. private bool m_decoded = false;
  142. public X509BasicConstraintsExtension() : base (CAPI.szOID_BASIC_CONSTRAINTS2) {
  143. m_decoded = true;
  144. }
  145. public X509BasicConstraintsExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint, bool critical) :
  146. base (CAPI.szOID_BASIC_CONSTRAINTS2, EncodeExtension(certificateAuthority, hasPathLengthConstraint, pathLengthConstraint), critical) {}
  147. public X509BasicConstraintsExtension (AsnEncodedData encodedBasicConstraints, bool critical) :
  148. base (CAPI.szOID_BASIC_CONSTRAINTS2, encodedBasicConstraints.RawData, critical) {}
  149. public bool CertificateAuthority {
  150. get {
  151. if (!m_decoded)
  152. DecodeExtension();
  153. return m_isCA;
  154. }
  155. }
  156. public bool HasPathLengthConstraint {
  157. get {
  158. if (!m_decoded)
  159. DecodeExtension();
  160. return m_hasPathLenConstraint;
  161. }
  162. }
  163. public int PathLengthConstraint {
  164. get {
  165. if (!m_decoded)
  166. DecodeExtension();
  167. return m_pathLenConstraint;
  168. }
  169. }
  170. public override void CopyFrom (AsnEncodedData asnEncodedData) {
  171. base.CopyFrom(asnEncodedData);
  172. m_decoded = false;
  173. }
  174. #if FEATURE_CORESYSTEM
  175. [SecuritySafeCritical]
  176. #endif
  177. private void DecodeExtension () {
  178. uint cbDecoded = 0;
  179. SafeLocalAllocHandle decoded = null;
  180. if (Oid.Value == CAPI.szOID_BASIC_CONSTRAINTS) {
  181. bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_BASIC_CONSTRAINTS),
  182. m_rawData,
  183. out decoded,
  184. out cbDecoded);
  185. if (result == false)
  186. throw new CryptographicException(Marshal.GetLastWin32Error());
  187. CAPI.CERT_BASIC_CONSTRAINTS_INFO pBasicConstraints = (CAPI.CERT_BASIC_CONSTRAINTS_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(),
  188. typeof(CAPI.CERT_BASIC_CONSTRAINTS_INFO));
  189. // take the first byte.
  190. byte[] isCA = new byte[1];
  191. Marshal.Copy(pBasicConstraints.SubjectType.pbData, isCA, 0, 1);
  192. m_isCA = (isCA[0] & CAPI.CERT_CA_SUBJECT_FLAG) != 0 ? true : false;
  193. m_hasPathLenConstraint = pBasicConstraints.fPathLenConstraint;
  194. m_pathLenConstraint = (int) pBasicConstraints.dwPathLenConstraint;
  195. } else {
  196. bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_BASIC_CONSTRAINTS2),
  197. m_rawData,
  198. out decoded,
  199. out cbDecoded);
  200. if (result == false)
  201. throw new CryptographicException(Marshal.GetLastWin32Error());
  202. CAPI.CERT_BASIC_CONSTRAINTS2_INFO pBasicConstraints2 = (CAPI.CERT_BASIC_CONSTRAINTS2_INFO) Marshal.PtrToStructure(decoded.DangerousGetHandle(),
  203. typeof(CAPI.CERT_BASIC_CONSTRAINTS2_INFO));
  204. m_isCA = pBasicConstraints2.fCA == 0 ? false : true;
  205. m_hasPathLenConstraint = pBasicConstraints2.fPathLenConstraint == 0 ? false : true;
  206. m_pathLenConstraint = (int) pBasicConstraints2.dwPathLenConstraint;
  207. }
  208. m_decoded = true;
  209. decoded.Dispose();
  210. }
  211. #if FEATURE_CORESYSTEM
  212. [SecuritySafeCritical]
  213. #endif
  214. private static unsafe byte[] EncodeExtension (bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint) {
  215. CAPI.CERT_BASIC_CONSTRAINTS2_INFO pBasicConstraints2 = new CAPI.CERT_BASIC_CONSTRAINTS2_INFO();
  216. pBasicConstraints2.fCA = certificateAuthority ? 1 : 0;
  217. pBasicConstraints2.fPathLenConstraint = hasPathLengthConstraint ? 1 : 0;
  218. if (hasPathLengthConstraint) {
  219. if (pathLengthConstraint < 0)
  220. throw new ArgumentOutOfRangeException("pathLengthConstraint", SR.GetString(SR.Arg_OutOfRange_NeedNonNegNum));
  221. pBasicConstraints2.dwPathLenConstraint = (uint) pathLengthConstraint;
  222. }
  223. byte[] encodedBasicConstraints = null;
  224. if (!CAPI.EncodeObject(CAPI.szOID_BASIC_CONSTRAINTS2, new IntPtr(&pBasicConstraints2), out encodedBasicConstraints))
  225. throw new CryptographicException(Marshal.GetLastWin32Error());
  226. return encodedBasicConstraints;
  227. }
  228. }
  229. public sealed class X509EnhancedKeyUsageExtension : X509Extension {
  230. private OidCollection m_enhancedKeyUsages;
  231. private bool m_decoded = false;
  232. public X509EnhancedKeyUsageExtension() : base (CAPI.szOID_ENHANCED_KEY_USAGE) {
  233. m_enhancedKeyUsages = new OidCollection();
  234. m_decoded = true;
  235. }
  236. public X509EnhancedKeyUsageExtension(OidCollection enhancedKeyUsages, bool critical) :
  237. base (CAPI.szOID_ENHANCED_KEY_USAGE, EncodeExtension(enhancedKeyUsages), critical) {}
  238. public X509EnhancedKeyUsageExtension(AsnEncodedData encodedEnhancedKeyUsages, bool critical) :
  239. base (CAPI.szOID_ENHANCED_KEY_USAGE, encodedEnhancedKeyUsages.RawData, critical) {}
  240. public OidCollection EnhancedKeyUsages {
  241. #if FEATURE_CORESYSTEM
  242. [SecuritySafeCritical]
  243. #endif
  244. get {
  245. if (!m_decoded)
  246. DecodeExtension();
  247. OidCollection oids = new OidCollection();
  248. foreach(Oid oid in m_enhancedKeyUsages) {
  249. oids.Add(oid);
  250. }
  251. return oids;
  252. }
  253. }
  254. public override void CopyFrom (AsnEncodedData asnEncodedData) {
  255. base.CopyFrom(asnEncodedData);
  256. m_decoded = false;
  257. }
  258. #if FEATURE_CORESYSTEM
  259. [SecuritySafeCritical]
  260. #endif
  261. private void DecodeExtension () {
  262. uint cbDecoded = 0;
  263. SafeLocalAllocHandle decoded = null;
  264. bool result = CAPI.DecodeObject(new IntPtr(CAPI.X509_ENHANCED_KEY_USAGE),
  265. m_rawData,
  266. out decoded,
  267. out cbDecoded);
  268. if (result == false)
  269. throw new CryptographicException(Marshal.GetLastWin32Error());
  270. CAPI.CERT_ENHKEY_USAGE pEnhKeyUsage = (CAPI.CERT_ENHKEY_USAGE) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CERT_ENHKEY_USAGE));
  271. m_enhancedKeyUsages = new OidCollection();
  272. for (int index = 0; index < pEnhKeyUsage.cUsageIdentifier; index++) {
  273. IntPtr pszOid = Marshal.ReadIntPtr(new IntPtr((long) pEnhKeyUsage.rgpszUsageIdentifier + index * Marshal.SizeOf(typeof(IntPtr))));
  274. string oidValue = Marshal.PtrToStringAnsi(pszOid);
  275. Oid oid = new Oid(oidValue, OidGroup.ExtensionOrAttribute, false);
  276. m_enhancedKeyUsages.Add(oid);
  277. }
  278. m_decoded = true;
  279. decoded.Dispose();
  280. }
  281. #if FEATURE_CORESYSTEM
  282. [SecuritySafeCritical]
  283. #endif
  284. private static unsafe byte[] EncodeExtension (OidCollection enhancedKeyUsages) {
  285. if (enhancedKeyUsages == null)
  286. throw new ArgumentNullException("enhancedKeyUsages");
  287. SafeLocalAllocHandle safeLocalAllocHandle = X509Utils.CopyOidsToUnmanagedMemory(enhancedKeyUsages);
  288. byte[] encodedEnhancedKeyUsages = null;
  289. using (safeLocalAllocHandle) {
  290. CAPI.CERT_ENHKEY_USAGE pEnhKeyUsage = new CAPI.CERT_ENHKEY_USAGE();
  291. pEnhKeyUsage.cUsageIdentifier = (uint) enhancedKeyUsages.Count;
  292. pEnhKeyUsage.rgpszUsageIdentifier = safeLocalAllocHandle.DangerousGetHandle();
  293. if (!CAPI.EncodeObject(CAPI.szOID_ENHANCED_KEY_USAGE, new IntPtr(&pEnhKeyUsage), out encodedEnhancedKeyUsages))
  294. throw new CryptographicException(Marshal.GetLastWin32Error());
  295. }
  296. return encodedEnhancedKeyUsages;
  297. }
  298. }
  299. public enum X509SubjectKeyIdentifierHashAlgorithm {
  300. Sha1 = 0,
  301. ShortSha1 = 1,
  302. CapiSha1 = 2,
  303. }
  304. public sealed class X509SubjectKeyIdentifierExtension : X509Extension {
  305. private string m_subjectKeyIdentifier;
  306. private bool m_decoded = false;
  307. public X509SubjectKeyIdentifierExtension() : base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER) {
  308. m_subjectKeyIdentifier = null;
  309. m_decoded = true;
  310. }
  311. #if FEATURE_CORESYSTEM
  312. [SecuritySafeCritical]
  313. #endif
  314. public X509SubjectKeyIdentifierExtension (string subjectKeyIdentifier, bool critical) :
  315. base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodeExtension(subjectKeyIdentifier), critical) {}
  316. #if FEATURE_CORESYSTEM
  317. [SecuritySafeCritical]
  318. #endif
  319. public X509SubjectKeyIdentifierExtension (byte[] subjectKeyIdentifier, bool critical) :
  320. base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodeExtension(subjectKeyIdentifier), critical) {}
  321. #if FEATURE_CORESYSTEM
  322. [SecuritySafeCritical]
  323. #endif
  324. public X509SubjectKeyIdentifierExtension (AsnEncodedData encodedSubjectKeyIdentifier, bool critical) :
  325. base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, encodedSubjectKeyIdentifier.RawData, critical) {}
  326. #if FEATURE_CORESYSTEM
  327. [SecuritySafeCritical]
  328. #endif
  329. public X509SubjectKeyIdentifierExtension (PublicKey key, bool critical) :
  330. base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodePublicKey(key, X509SubjectKeyIdentifierHashAlgorithm.Sha1), critical) {}
  331. #if FEATURE_CORESYSTEM
  332. [SecuritySafeCritical]
  333. #endif
  334. public X509SubjectKeyIdentifierExtension (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm, bool critical) :
  335. base (CAPI.szOID_SUBJECT_KEY_IDENTIFIER, EncodePublicKey(key, algorithm), critical) {}
  336. public string SubjectKeyIdentifier {
  337. #if FEATURE_CORESYSTEM
  338. [SecuritySafeCritical]
  339. #endif
  340. get {
  341. if (!m_decoded)
  342. DecodeExtension();
  343. return m_subjectKeyIdentifier;
  344. }
  345. }
  346. public override void CopyFrom (AsnEncodedData asnEncodedData) {
  347. base.CopyFrom(asnEncodedData);
  348. m_decoded = false;
  349. }
  350. #if FEATURE_CORESYSTEM
  351. [SecuritySafeCritical]
  352. #endif
  353. private void DecodeExtension () {
  354. uint cbDecoded = 0;
  355. SafeLocalAllocHandle decoded = null;
  356. SafeLocalAllocHandle pb = X509Utils.StringToAnsiPtr(CAPI.szOID_SUBJECT_KEY_IDENTIFIER);
  357. bool result = CAPI.DecodeObject(pb.DangerousGetHandle(),
  358. m_rawData,
  359. out decoded,
  360. out cbDecoded);
  361. if (!result)
  362. throw new CryptographicException(Marshal.GetLastWin32Error());
  363. CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = (CAPI.CRYPTOAPI_BLOB) Marshal.PtrToStructure(decoded.DangerousGetHandle(), typeof(CAPI.CRYPTOAPI_BLOB));
  364. byte[] hexArray = CAPI.BlobToByteArray(pSubjectKeyIdentifier);
  365. m_subjectKeyIdentifier = X509Utils.EncodeHexString(hexArray);
  366. m_decoded = true;
  367. decoded.Dispose();
  368. pb.Dispose();
  369. }
  370. private static unsafe byte[] EncodeExtension (string subjectKeyIdentifier) {
  371. if (subjectKeyIdentifier == null)
  372. throw new ArgumentNullException("subjectKeyIdentifier");
  373. return EncodeExtension(X509Utils.DecodeHexString(subjectKeyIdentifier));
  374. }
  375. #if FEATURE_CORESYSTEM
  376. [SecuritySafeCritical]
  377. #endif
  378. private static unsafe byte[] EncodeExtension (byte[] subjectKeyIdentifier) {
  379. if (subjectKeyIdentifier == null)
  380. throw new ArgumentNullException("subjectKeyIdentifier");
  381. if (subjectKeyIdentifier.Length == 0)
  382. throw new ArgumentException("subjectKeyIdentifier");
  383. byte[] encodedSubjectKeyIdentifier = null;
  384. fixed (byte* pb = subjectKeyIdentifier) {
  385. CAPI.CRYPTOAPI_BLOB pSubjectKeyIdentifier = new CAPI.CRYPTOAPI_BLOB();
  386. pSubjectKeyIdentifier.pbData = new IntPtr(pb);
  387. pSubjectKeyIdentifier.cbData = (uint) subjectKeyIdentifier.Length;
  388. if (!CAPI.EncodeObject(CAPI.szOID_SUBJECT_KEY_IDENTIFIER, new IntPtr(&pSubjectKeyIdentifier), out encodedSubjectKeyIdentifier))
  389. throw new CryptographicException(Marshal.GetLastWin32Error());
  390. }
  391. return encodedSubjectKeyIdentifier;
  392. }
  393. // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs.
  394. #if FEATURE_CORESYSTEM
  395. [SecuritySafeCritical]
  396. #endif
  397. private static unsafe SafeLocalAllocHandle EncodePublicKey (PublicKey key) {
  398. SafeLocalAllocHandle publicKeyInfo = SafeLocalAllocHandle.InvalidHandle;
  399. CAPI.CERT_PUBLIC_KEY_INFO2 * pPublicKeyInfo = null;
  400. string objId = key.Oid.Value;
  401. byte[] encodedParameters = key.EncodedParameters.RawData;
  402. byte[] encodedKeyValue = key.EncodedKeyValue.RawData;
  403. uint cbPublicKeyInfo = (uint) (Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO2)) +
  404. X509Utils.AlignedLength((uint) (objId.Length + 1)) +
  405. X509Utils.AlignedLength((uint) encodedParameters.Length) +
  406. encodedKeyValue.Length);
  407. publicKeyInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbPublicKeyInfo));
  408. pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *) publicKeyInfo.DangerousGetHandle();
  409. IntPtr pszObjId = new IntPtr((long) pPublicKeyInfo + Marshal.SizeOf(typeof(CAPI.CERT_PUBLIC_KEY_INFO2)));
  410. IntPtr pbParameters = new IntPtr((long) pszObjId + X509Utils.AlignedLength(((uint) (objId.Length + 1))));
  411. IntPtr pbPublicKey = new IntPtr((long) pbParameters + X509Utils.AlignedLength((uint) encodedParameters.Length));
  412. pPublicKeyInfo->Algorithm.pszObjId = pszObjId;
  413. byte[] szObjId = new byte[objId.Length + 1];
  414. Encoding.ASCII.GetBytes(objId, 0, objId.Length, szObjId, 0);
  415. Marshal.Copy(szObjId, 0, pszObjId, szObjId.Length);
  416. if (encodedParameters.Length > 0) {
  417. pPublicKeyInfo->Algorithm.Parameters.cbData = (uint) encodedParameters.Length;
  418. pPublicKeyInfo->Algorithm.Parameters.pbData = pbParameters;
  419. Marshal.Copy(encodedParameters, 0, pbParameters, encodedParameters.Length);
  420. }
  421. pPublicKeyInfo->PublicKey.cbData = (uint) encodedKeyValue.Length;
  422. pPublicKeyInfo->PublicKey.pbData = pbPublicKey;
  423. Marshal.Copy(encodedKeyValue, 0, pbPublicKey, encodedKeyValue.Length);
  424. return publicKeyInfo;
  425. }
  426. #if FEATURE_CORESYSTEM
  427. [SecuritySafeCritical]
  428. #endif
  429. private static unsafe byte[] EncodePublicKey (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm) {
  430. if (key == null)
  431. throw new ArgumentNullException("key");
  432. // Construct CERT_PUBLIC_KEY_INFO2 in unmanged memory from given encoded blobs.
  433. SafeLocalAllocHandle publicKeyInfo = EncodePublicKey(key);
  434. CAPI.CERT_PUBLIC_KEY_INFO2 * pPublicKeyInfo = (CAPI.CERT_PUBLIC_KEY_INFO2 *) publicKeyInfo.DangerousGetHandle();
  435. byte [] buffer = new byte[20];
  436. byte [] identifier = null;
  437. fixed (byte * pBuffer = buffer) {
  438. uint cbData = (uint)buffer.Length;
  439. IntPtr pbData = new IntPtr(pBuffer);
  440. try {
  441. if ((X509SubjectKeyIdentifierHashAlgorithm.Sha1 == algorithm)
  442. || (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm)) {
  443. //+=================================================================
  444. // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of
  445. // the value of the BIT STRING subjectPublicKey (excluding the tag,
  446. // length, and number of unused bits).
  447. if (!CAPI.CryptHashCertificate(
  448. IntPtr.Zero, // hCryptProv
  449. CAPI.CALG_SHA1,
  450. 0, // dwFlags,
  451. pPublicKeyInfo->PublicKey.pbData,
  452. pPublicKeyInfo->PublicKey.cbData,
  453. pbData,
  454. new IntPtr(&cbData)))
  455. throw new CryptographicException(Marshal.GetHRForLastWin32Error());
  456. }
  457. //+=================================================================
  458. // Microsoft convention: The keyIdentifier is composed of the
  459. // 160-bit SHA-1 hash of the encoded subjectPublicKey BITSTRING
  460. // (including the tag, length, and number of unused bits).
  461. else if (X509SubjectKeyIdentifierHashAlgorithm.CapiSha1 == algorithm) {
  462. if (!CAPI.CryptHashPublicKeyInfo(
  463. IntPtr.Zero, // hCryptProv
  464. CAPI.CALG_SHA1,
  465. 0, // dwFlags,
  466. CAPI.X509_ASN_ENCODING,
  467. new IntPtr(pPublicKeyInfo),
  468. pbData,
  469. new IntPtr(&cbData))) {
  470. throw new CryptographicException(Marshal.GetHRForLastWin32Error());
  471. }
  472. } else {
  473. throw new ArgumentException("algorithm");
  474. }
  475. //+=================================================================
  476. // (2) The keyIdentifier is composed of a four bit type field with
  477. // the value 0100 followed by the least significant 60 bits of the
  478. // SHA-1 hash of the value of the BIT STRING subjectPublicKey
  479. // (excluding the tag, length, and number of unused bit string bits)
  480. if (X509SubjectKeyIdentifierHashAlgorithm.ShortSha1 == algorithm) {
  481. identifier = new byte[8];
  482. Array.Copy(buffer, buffer.Length - 8, identifier, 0, identifier.Length);
  483. identifier[0] &= 0x0f;
  484. identifier[0] |= 0x40;
  485. } else {
  486. identifier = buffer;
  487. // return the meaningful part only
  488. if (buffer.Length > (int)cbData) {
  489. identifier = new byte[cbData];
  490. Array.Copy(buffer, 0, identifier, 0, identifier.Length);
  491. }
  492. }
  493. } finally {
  494. publicKeyInfo.Dispose();
  495. }
  496. }
  497. return EncodeExtension(identifier);
  498. }
  499. }
  500. public sealed class X509ExtensionCollection : ICollection {
  501. private ArrayList m_list = new ArrayList();
  502. //
  503. // Constructors.
  504. //
  505. public X509ExtensionCollection() {}
  506. #if FEATURE_CORESYSTEM
  507. [SecuritySafeCritical]
  508. #endif
  509. internal unsafe X509ExtensionCollection(SafeCertContextHandle safeCertContextHandle) {
  510. using (SafeCertContextHandle certContext = CAPI.CertDuplicateCertificateContext(safeCertContextHandle)) {
  511. CAPI.CERT_CONTEXT pCertContext = *((CAPI.CERT_CONTEXT*) certContext.DangerousGetHandle());
  512. CAPI.CERT_INFO pCertInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
  513. uint cExtensions = pCertInfo.cExtension;
  514. IntPtr rgExtensions = pCertInfo.rgExtension;
  515. for (uint index = 0; index < cExtensions; index++) {
  516. X509Extension extension = new X509Extension(new IntPtr((long)rgExtensions + (index * Marshal.SizeOf(typeof(CAPI.CERT_EXTENSION)))));
  517. X509Extension customExtension = CryptoConfig.CreateFromName(extension.Oid.Value) as X509Extension;
  518. if (customExtension != null) {
  519. customExtension.CopyFrom(extension);
  520. extension = customExtension;
  521. }
  522. Add(extension);
  523. }
  524. }
  525. }
  526. public X509Extension this[int index] {
  527. get {
  528. if (index < 0)
  529. throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumNotStarted));
  530. if (index >= m_list.Count)
  531. throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_Index));
  532. return (X509Extension) m_list[index];
  533. }
  534. }
  535. // Indexer using an OID friendly name or value.
  536. public X509Extension this[string oid] {
  537. get {
  538. // If we were passed the friendly name, retrieve the value string.
  539. string oidValue = X509Utils.FindOidInfoWithFallback(CAPI.CRYPT_OID_INFO_NAME_KEY, oid, OidGroup.ExtensionOrAttribute);
  540. if (oidValue == null)
  541. oidValue = oid;
  542. foreach (X509Extension extension in m_list) {
  543. if (String.Compare(extension.Oid.Value, oidValue, StringComparison.OrdinalIgnoreCase) == 0)
  544. return extension;
  545. }
  546. return null;
  547. }
  548. }
  549. public int Count {
  550. get {
  551. return m_list.Count;
  552. }
  553. }
  554. public int Add (X509Extension extension) {
  555. if (extension == null)
  556. throw new ArgumentNullException("extension");
  557. return m_list.Add(extension);
  558. }
  559. public X509ExtensionEnumerator GetEnumerator() {
  560. return new X509ExtensionEnumerator(this);
  561. }
  562. /// <internalonly/>
  563. IEnumerator IEnumerable.GetEnumerator() {
  564. return new X509ExtensionEnumerator(this);
  565. }
  566. /// <internalonly/>
  567. void ICollection.CopyTo(Array array, int index) {
  568. if (array == null)
  569. throw new ArgumentNullException("array");
  570. if (array.Rank != 1)
  571. throw new ArgumentException(SR.GetString(SR.Arg_RankMultiDimNotSupported));
  572. if (index < 0 || index >= array.Length)
  573. throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_Index));
  574. if (index + this.Count > array.Length)
  575. throw new ArgumentException(SR.GetString(SR.Argument_InvalidOffLen));
  576. for (int i=0; i < this.Count; i++) {
  577. array.SetValue(this[i], index);
  578. index++;
  579. }
  580. }
  581. public void CopyTo(X509Extension[] array, int index) {
  582. ((ICollection)this).CopyTo(array, index);
  583. }
  584. public bool IsSynchronized {
  585. get {
  586. return false;
  587. }
  588. }
  589. public Object SyncRoot {
  590. get {
  591. return this;
  592. }
  593. }
  594. }
  595. public sealed class X509ExtensionEnumerator : IEnumerator {
  596. private X509ExtensionCollection m_extensions;
  597. private int m_current;
  598. private X509ExtensionEnumerator() {}
  599. internal X509ExtensionEnumerator(X509ExtensionCollection extensions) {
  600. m_extensions = extensions;
  601. m_current = -1;
  602. }
  603. public X509Extension Current {
  604. get {
  605. return m_extensions[m_current];
  606. }
  607. }
  608. /// <internalonly/>
  609. Object IEnumerator.Current {
  610. get {
  611. return (Object) m_extensions[m_current];
  612. }
  613. }
  614. public bool MoveNext() {
  615. if (m_current == ((int) m_extensions.Count - 1))
  616. return false;
  617. m_current++;
  618. return true;
  619. }
  620. public void Reset() {
  621. m_current = -1;
  622. }
  623. }
  624. }