PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_Main/Languages/Ruby/Libraries.LCA_RESTRICTED/OpenSSL/OpenSSL.cs

#
C# | 466 lines | 292 code | 80 blank | 94 comment | 28 complexity | 961d5f6d44ec431172cf431f8022d96b MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Runtime.InteropServices;
  17. using IronRuby.Builtins;
  18. using IronRuby.Runtime;
  19. using Microsoft.Scripting.Math;
  20. using Microsoft.Scripting.Runtime;
  21. using Crypto = System.Security.Cryptography;
  22. using System.Text;
  23. using System.Security.Cryptography.X509Certificates;
  24. using System.Security.Cryptography;
  25. using System.Globalization;
  26. namespace IronRuby.StandardLibrary.OpenSsl {
  27. [RubyModule("OpenSSL")]
  28. public static class OpenSsl {
  29. // TODO: constants
  30. // Config,HMACError,PKCS12,Random,OPENSSL_VERSION,PKCS7,BN,ConfigError,PKey,Engine,BNError,Netscape,OCSP
  31. // OpenSSLError,CipherError,SSL,VERSION,X509,ASN1,OPENSSL_VERSION_NUMBER,Cipher
  32. [RubyConstant]
  33. public const string OPENSSL_VERSION = "OpenSSL 0.9.8d 28 Sep 2006";
  34. [RubyConstant]
  35. public const double OPENSSL_VERSION_NUMBER = 9470031;
  36. [RubyConstant]
  37. public const string VERSION = "1.0.0";
  38. [RubyModule("Digest")]
  39. public static class DigestFactory {
  40. // TODO: constants:
  41. // SHA224,MDC2,DSS1,SHA512,SHA1,MD5,DSS,SHA384,SHA,MD4,SHA256,DigestError,RIPEMD160,MD2
  42. [RubyClass("Digest")]
  43. public class Digest {
  44. private Crypto.HMAC _algorithm;
  45. public Crypto.HMAC Algorithm {
  46. get { return _algorithm; }
  47. }
  48. protected Digest() {
  49. }
  50. [RubyConstructor]
  51. public static Digest/*!*/ CreateDigest(RubyClass/*!*/ self, [NotNull]MutableString/*!*/ algorithmName) {
  52. return Initialize(new Digest(), algorithmName);
  53. }
  54. // Reinitialization. Not called when a factory/non-default ctor is called.
  55. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)]
  56. public static Digest/*!*/ Initialize(Digest/*!*/ self, [NotNull]MutableString/*!*/ algorithmName) {
  57. Crypto.HMAC algorithm;
  58. #if SILVERLIGHT
  59. switch (algorithmName.ToString()) {
  60. case "SHA1": algorithm = new Crypto.HMACSHA1(); break;
  61. case "SHA256": algorithm = new Crypto.HMACSHA256(); break;
  62. default: algorithm = null; break;
  63. }
  64. #else
  65. algorithm = Crypto.HMAC.Create("HMAC" + algorithmName.ConvertToString());
  66. #endif
  67. if (algorithm == null) {
  68. throw RubyExceptions.CreateRuntimeError("Unsupported digest algorithm ({0}).", algorithmName);
  69. }
  70. self._algorithm = algorithm;
  71. return self;
  72. }
  73. // new(string) -> digest
  74. [RubyMethod("reset")]
  75. public static Digest/*!*/ Reset(Digest/*!*/ self) {
  76. self._algorithm.Clear();
  77. return self;
  78. }
  79. // update(string) -> aString
  80. // finish -> aString
  81. [RubyMethod("name")]
  82. public static MutableString/*!*/ Name(Digest/*!*/ self) {
  83. return MutableString.CreateAscii(self._algorithm.HashName);
  84. }
  85. [RubyMethod("digest_size")]
  86. public static int Seed(Digest/*!*/ self) {
  87. return self._algorithm.OutputBlockSize;
  88. }
  89. //TODO: Properly disable this with BuildConfig
  90. [RubyMethod("digest")]
  91. public static MutableString/*!*/ BlankDigest(Digest/*!*/ self) {
  92. #if !SILVERLIGHT
  93. // TODO: This support only SHA1, It should use self._algorithm but It is not
  94. byte[] blank_data = Encoding.UTF8.GetBytes("");
  95. byte[] hash = new SHA1CryptoServiceProvider().ComputeHash(blank_data);
  96. return MutableString.CreateBinary(hash);
  97. #else
  98. throw new NotSupportedException();
  99. #endif
  100. }
  101. //TODO: Properly disable with BuildConfig
  102. [RubyMethod("hexdigest")]
  103. public static MutableString/*!*/ BlankHexDigest(Digest/*!*/ self) {
  104. #if !SILVERLIGHT
  105. byte[] blank_data = Encoding.UTF8.GetBytes("");
  106. byte[] hash = new SHA1CryptoServiceProvider().ComputeHash(blank_data);
  107. return MutableString.CreateAscii(BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant());
  108. #else
  109. throw new NotSupportedException();
  110. #endif
  111. }
  112. }
  113. }
  114. [RubyClass("HMAC")]
  115. public class HMAC {
  116. internal static byte[] Digest(DigestFactory.Digest digest, MutableString key, MutableString data) {
  117. // TODO: does MRI really modify the digest object?
  118. digest.Algorithm.Key = key.ConvertToBytes();
  119. byte[] hash = digest.Algorithm.ComputeHash(data.ConvertToBytes());
  120. return hash;
  121. }
  122. [RubyMethod("hexdigest", RubyMethodAttributes.PublicSingleton)]
  123. public static MutableString/*!*/ HexDigest(RubyClass/*!*/ self,
  124. [NotNull]DigestFactory.Digest/*!*/ digest,
  125. [NotNull]MutableString/*!*/ key,
  126. [NotNull]MutableString/*!*/ data) {
  127. byte[] hash = Digest(digest, key, data);
  128. // TODO (opt):
  129. return MutableString.CreateAscii(BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant());
  130. }
  131. [RubyMethod("digest", RubyMethodAttributes.PublicSingleton)]
  132. public static MutableString/*!*/ Digest(RubyClass/*!*/ self,
  133. [NotNull]DigestFactory.Digest/*!*/ digest,
  134. [NotNull]MutableString/*!*/ key,
  135. [NotNull]MutableString/*!*/ data) {
  136. byte[] hash = Digest(digest, key, data);
  137. return MutableString.CreateBinary(hash);
  138. }
  139. // HMAC.new(key, digest) -> hmac
  140. // update(string) -> self
  141. // digest -> aString
  142. // hexdigest -> aString
  143. // reset -> self
  144. }
  145. [RubyModule("Random")]
  146. public static class RandomModule {
  147. // This is a no-op method since our random number generator uses the .NET crypto random number generator
  148. // that gets its seed values from the OS
  149. [RubyMethod("seed", RubyMethodAttributes.PublicSingleton)]
  150. public static MutableString/*!*/ Seed(RubyModule/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ seed) {
  151. return seed;
  152. }
  153. [RubyMethod("pseudo_bytes", RubyMethodAttributes.PublicSingleton)]
  154. [RubyMethod("random_bytes", RubyMethodAttributes.PublicSingleton)]
  155. public static MutableString/*!*/ RandomBytes(RubyModule/*!*/ self, [DefaultProtocol]int length) {
  156. if (length < 0) {
  157. throw RubyExceptions.CreateArgumentError("negative string size");
  158. }
  159. if (length == 0) {
  160. return MutableString.CreateEmpty();
  161. }
  162. byte[] data = new byte[length];
  163. var generator = new Crypto.RNGCryptoServiceProvider();
  164. generator.GetBytes(data);
  165. return MutableString.CreateBinary(data);
  166. }
  167. // add(str, entropy) -> self
  168. // load_random_file(filename) -> true
  169. }
  170. [RubyClass("BN")]
  171. public class BN {
  172. // new => aBN
  173. // new(bn) => aBN
  174. // new(string) => aBN
  175. // new(string, 0 | 2 | 10 | 16) => aBN
  176. [RubyMethod("rand", RubyMethodAttributes.PublicSingleton)]
  177. public static BigInteger/*!*/ Rand(RubyClass/*!*/ self, [DefaultProtocol]int bits, [DefaultProtocol, Optional]int someFlag, [Optional]bool otherFlag) { // TODO: figure out someFlag and otherFlag
  178. byte[] data = new byte[bits >> 3];
  179. var generator = new Crypto.RNGCryptoServiceProvider();
  180. generator.GetBytes(data);
  181. uint[] transformed = new uint[data.Length >> 2];
  182. int j = 0;
  183. for (int i = 0; i < transformed.Length; ++i) {
  184. transformed[i] = data[j] + (uint)(data[j + 1] << 8) + (uint)(data[j + 2] << 16) + (uint)(data[j + 3] << 24);
  185. j += 4;
  186. }
  187. return new BigInteger(1, transformed);
  188. }
  189. }
  190. [RubyModule("X509")]
  191. public static class X509 {
  192. [RubyClass("CertificateError", Extends = typeof(CryptographicException), Inherits = typeof(ExternalException))]
  193. public class CryptographicExceptionOps {
  194. [RubyConstructor]
  195. public static CryptographicException/*!*/ Create(RubyClass/*!*/ self, [DefaultProtocol, DefaultParameterValue(null)]MutableString message) {
  196. CryptographicException result = new CryptographicException(RubyExceptions.MakeMessage(ref message, "Not enought data."));
  197. RubyExceptionData.InitializeException(result, message);
  198. return result;
  199. }
  200. }
  201. // TODO: Constants
  202. [RubyClass("Certificate")]
  203. public class Certificate {
  204. private X509Certificate/*!*/ _certificate;
  205. [RubyConstructor]
  206. public static Certificate/*!*/ CreateCertificate(RubyClass/*!*/ self) {
  207. return Initialize(new Certificate(), null);
  208. }
  209. [RubyConstructor]
  210. public static Certificate/*!*/ CreateCertificate(RubyClass/*!*/ self, MutableString/*!*/ data) {
  211. return Initialize(new Certificate(), data);
  212. }
  213. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)]
  214. public static Certificate/*!*/ Initialize(Certificate/*!*/ self, MutableString/*!*/ data) {
  215. if (data == null) {
  216. self._certificate = new X509Certificate();
  217. } else {
  218. self._certificate = new X509Certificate(data.ToByteArray());
  219. }
  220. return self;
  221. }
  222. // add_extension
  223. // check_private_key
  224. // extensions
  225. // extensions=
  226. private static string OpenSSLFormat(string x509String) {
  227. string[] pairs = x509String.Split(',');
  228. Array.Sort<string>(pairs);
  229. StringBuilder sb = new StringBuilder();
  230. foreach (var val in pairs) {
  231. sb.AppendFormat("/{0}", val.Trim());
  232. }
  233. return sb.ToString();
  234. }
  235. // issuer=
  236. [RubyMethod("issuer")]
  237. public static MutableString Issuer(Certificate/*!*/ self) {
  238. if (self._certificate.Handle == IntPtr.Zero) {
  239. return null;
  240. } else {
  241. return MutableString.CreateAscii(OpenSSLFormat(self._certificate.Issuer));
  242. }
  243. }
  244. // not_after => time
  245. // not_after=
  246. // not_before => time
  247. // not_before=
  248. [RubyMethod("public_key")]
  249. public static MutableString PublicKey(Certificate/*!*/ self) {
  250. if (self._certificate.Handle == IntPtr.Zero) {
  251. // TODO: Raise OpenSSL::X509::CertificateError
  252. return MutableString.CreateEmpty();
  253. } else {
  254. return MutableString.CreateAscii(self._certificate.GetPublicKeyString());
  255. }
  256. }
  257. // public_key=
  258. private int SerailNumber {
  259. get {
  260. if (_certificate.Handle == IntPtr.Zero) {
  261. return 0;
  262. } else {
  263. return int.Parse(_certificate.GetSerialNumberString(), CultureInfo.InvariantCulture);
  264. }
  265. }
  266. }
  267. [RubyMethod("serial")]
  268. public static int Serial(Certificate/*!*/ self) {
  269. return self.SerailNumber;
  270. }
  271. // serial=
  272. // sign(key, digest) => self
  273. // signature_algorithm
  274. [RubyMethod("subject")]
  275. public static MutableString Subject(Certificate/*!*/ self) {
  276. if (self._certificate.Handle == IntPtr.Zero) {
  277. return null;
  278. } else {
  279. return MutableString.CreateAscii(OpenSSLFormat(self._certificate.Subject));
  280. }
  281. }
  282. // subject=
  283. // to_der
  284. // to_pem
  285. [RubyMethod("inspect")]
  286. [RubyMethod("to_s")]
  287. public static MutableString ToString(RubyContext/*!*/ context, Certificate/*!*/ self) {
  288. using (IDisposable handle = RubyUtils.InfiniteInspectTracker.TrackObject(self)) {
  289. // #<OpenSSL::X509::Certificate subject=, issuer=, serial=0, not_before=nil, not_after=nil>
  290. var result = MutableString.CreateEmpty();
  291. result.Append("#<");
  292. result.Append(context.Inspect(context.GetClassOf(self)));
  293. if (handle == null) {
  294. return result.Append(":...>");
  295. }
  296. bool empty = self._certificate.Handle == IntPtr.Zero;
  297. result.AppendFormat(" subject={0}, issuer={1}, serial={2}, not_before=nil, not_after=nil>",
  298. empty ? "" : OpenSSLFormat(self._certificate.Subject),
  299. empty ? "" : OpenSSLFormat(self._certificate.Issuer),
  300. empty ? 0 : self.SerailNumber
  301. );
  302. return result;
  303. }
  304. }
  305. // to_text
  306. // verify
  307. [RubyMethod("version")]
  308. public static int Version(Certificate/*!*/ self) {
  309. if (self._certificate.Handle == IntPtr.Zero) {
  310. return 0;
  311. } else {
  312. return 2;
  313. }
  314. }
  315. // version=
  316. }
  317. [RubyClass("Name")]
  318. public class Name {
  319. // new => name
  320. // new(string) => name
  321. // new(dn) => name
  322. // new(dn, template) => name
  323. // add_entry(oid, value [, type]) => self
  324. // to_s => string
  325. // to_s(integer) => string
  326. // to_a => [[name, data, type], ...]
  327. // hash => integer
  328. // to_der => string
  329. // parse(string) => name
  330. }
  331. }
  332. [RubyModule("PKey")]
  333. public static class PKey {
  334. [RubyClass("RSA")]
  335. public class RSA {
  336. // RSA.new([size | encoded_key] [, pass]) -> rsa
  337. // new(2048) -> rsa
  338. // new(File.read("rsa.pem")) -> rsa
  339. // new(File.read("rsa.pem"), "mypassword") -> rsa
  340. // initialize
  341. // generate(size [, exponent]) -> rsa
  342. // public? -> true (The return value is always true since every private key is also a public key)
  343. // private? -> true | false
  344. // to_pem -> aString
  345. // to_pem(cipher, pass) -> aString
  346. // to_der -> aString
  347. // public_encrypt(string [, padding]) -> aString
  348. // public_decrypt(string [, padding]) -> aString
  349. // private_encrypt(string [, padding]) -> aString
  350. // private_decrypt(string [, padding]) -> aString
  351. // params -> hash
  352. // to_text -> aString
  353. // public_key -> aRSA
  354. // inspect
  355. // to_s
  356. }
  357. }
  358. [RubyClass("OpenSSLError"), Serializable]
  359. public class OpenSSLError : SystemException {
  360. private const string/*!*/ M = "OpenSSL error";
  361. public OpenSSLError() : this(null, null) { }
  362. public OpenSSLError(string message) : this(message, null) { }
  363. public OpenSSLError(string message, Exception inner) : base(RubyExceptions.MakeMessage(message, M), inner) { }
  364. public OpenSSLError(MutableString message) : base(RubyExceptions.MakeMessage(ref message, M)) { RubyExceptionData.InitializeException(this, message); }
  365. #if !SILVERLIGHT
  366. protected OpenSSLError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
  367. : base(info, context) { }
  368. #endif
  369. }
  370. [RubyModule("SSL")]
  371. public static class SSL {
  372. [RubyClass("SSLError"), Serializable]
  373. public class SSLError : OpenSSLError {
  374. private const string/*!*/ M = "SSL error";
  375. public SSLError() : this(null, null) { }
  376. public SSLError(string message) : this(message, null) { }
  377. public SSLError(string message, Exception inner) : base(RubyExceptions.MakeMessage(message, M), inner) { }
  378. public SSLError(MutableString message) : base(RubyExceptions.MakeMessage(ref message, M)) { RubyExceptionData.InitializeException(this, message); }
  379. #if !SILVERLIGHT
  380. protected SSLError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
  381. : base(info, context) { }
  382. #endif
  383. }
  384. }
  385. }
  386. }