You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
9.7 KiB

4 years ago
  1. #if MYSQL_6_10
  2. // Copyright © 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using System;
  24. using System.Collections.Generic;
  25. using System.IO;
  26. using System.Linq;
  27. using System.Security.Cryptography;
  28. using System.Text;
  29. #if NETSTANDARD1_3
  30. using AliasText = Externals.MySql.Data.MySqlClient.Framework.NetStandard1_3;
  31. #else
  32. using AliasText = System.Text;
  33. #endif
  34. namespace Externals.MySql.Data.MySqlClient.Authentication
  35. {
  36. internal class MySqlPemReader
  37. {
  38. #if NETSTANDARD1_3
  39. public static RSA ConvertPemToRSAProvider(byte[] rawPublicKey)
  40. #else
  41. public static RSACryptoServiceProvider ConvertPemToRSAProvider(byte[] rawPublicKey)
  42. #endif
  43. {
  44. byte[] decodedKey = DecodeOpenSslKey(rawPublicKey);
  45. return DecodeX509Key(decodedKey);
  46. }
  47. #if NETSTANDARD1_3
  48. static RSA DecodeX509Key(byte[] key)
  49. #else
  50. static RSACryptoServiceProvider DecodeX509Key(byte[] key)
  51. #endif
  52. {
  53. if (key == null) return null;
  54. byte[] oidSequence = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
  55. using (var memoryStream = new MemoryStream(key))
  56. {
  57. using (var reader = new BinaryReader(memoryStream))
  58. {
  59. try
  60. {
  61. var bytes = reader.ReadUInt16();
  62. switch (bytes)
  63. {
  64. case 0x8130:
  65. reader.ReadByte();
  66. break;
  67. case 0x8230:
  68. reader.ReadInt16();
  69. break;
  70. default:
  71. return null;
  72. }
  73. var sequence = reader.ReadBytes(15);
  74. // Compare arrays.
  75. bool arraysAreEqual = true;
  76. if (sequence.Length == oidSequence.Length)
  77. {
  78. for (int i = 0; i < oidSequence.Length; i++)
  79. if (sequence[i] != oidSequence[i])
  80. {
  81. arraysAreEqual = false;
  82. }
  83. }
  84. if (!arraysAreEqual) return null;
  85. bytes = reader.ReadUInt16();
  86. if (bytes == 0x8103) reader.ReadByte();
  87. else if (bytes == 0x8203) reader.ReadInt16();
  88. else return null;
  89. if (reader.ReadByte() != 0x00) return null;
  90. bytes = reader.ReadUInt16();
  91. if (bytes == 0x8130) reader.ReadByte();
  92. else if (bytes == 0x8230) reader.ReadInt16();
  93. else return null;
  94. bytes = reader.ReadUInt16();
  95. byte lowByte = 0x00;
  96. byte highByte = 0x00;
  97. if (bytes == 0x8102) lowByte = reader.ReadByte();
  98. else if (bytes == 0x8202)
  99. {
  100. highByte = reader.ReadByte();
  101. lowByte = reader.ReadByte();
  102. }
  103. else return null;
  104. int modulusSize = BitConverter.ToInt32(new byte[] { lowByte, highByte, 0x00, 0x00 }, 0);
  105. byte firstByte = reader.ReadByte();
  106. reader.BaseStream.Seek(-1, SeekOrigin.Current);
  107. if (firstByte == 0x00)
  108. {
  109. reader.ReadByte();
  110. modulusSize -= 1;
  111. }
  112. // Read modulus.
  113. byte[] modulus = reader.ReadBytes(modulusSize);
  114. if (reader.ReadByte() != 0x02) return null;
  115. // Read exponent.
  116. byte[] exponent = reader.ReadBytes(reader.ReadByte());
  117. #if NETSTANDARD1_3
  118. RSA rsa = RSA.Create();
  119. #else
  120. RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
  121. #endif
  122. RSAParameters rsaKeyInfo = new RSAParameters
  123. {
  124. Modulus = modulus,
  125. Exponent = exponent
  126. };
  127. rsa.ImportParameters(rsaKeyInfo);
  128. return rsa;
  129. }
  130. catch (Exception)
  131. {
  132. return null;
  133. }
  134. }
  135. }
  136. }
  137. static byte[] DecodeOpenSslKey(byte[] rawPublicKey)
  138. {
  139. if (rawPublicKey == null) return null;
  140. // Remove line breaks and carriage returns.
  141. rawPublicKey = rawPublicKey.Where(b => b != 0x0D).ToArray();
  142. rawPublicKey = rawPublicKey.Where(b => b != 0x0A).ToArray();
  143. // Trim.
  144. rawPublicKey = TrimByteArray(rawPublicKey);
  145. // Remove header and footer
  146. byte[] headerSequence = { 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D };
  147. byte[] footerSequence = { 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D };
  148. if (!StartsWith(rawPublicKey, headerSequence) || !EndsWith(rawPublicKey, footerSequence)) return null;
  149. byte[] formattedRawPublicKey = new byte[rawPublicKey.Length - headerSequence.Length - footerSequence.Length];
  150. Array.Copy(rawPublicKey, headerSequence.Length, formattedRawPublicKey, 0, formattedRawPublicKey.Length);
  151. byte[] binaryKey;
  152. try
  153. {
  154. binaryKey = Convert.FromBase64String(AliasText.Encoding.Default.GetString(formattedRawPublicKey));
  155. }
  156. catch (FormatException)
  157. {
  158. return null;
  159. }
  160. return binaryKey;
  161. }
  162. static byte[] DecodeOpenSslKey2(byte[] rawPublicKey)
  163. {
  164. if (rawPublicKey == null) return null;
  165. var pem = AliasText.Encoding.Default.GetString(rawPublicKey);
  166. pem = pem.Replace(Environment.NewLine, "");
  167. const string header = "-----BEGIN PUBLIC KEY-----";
  168. const string footer = "-----END PUBLIC KEY-----";
  169. pem = pem.Trim();
  170. byte[] binaryKey;
  171. if (!pem.StartsWith(header) || !pem.EndsWith(footer))
  172. return null;
  173. StringBuilder builder = new StringBuilder(pem);
  174. builder.Replace(header, "");
  175. builder.Replace(footer, "");
  176. string formattedPem = builder.ToString().Trim();
  177. try
  178. {
  179. binaryKey = Convert.FromBase64String(formattedPem);
  180. }
  181. catch (FormatException)
  182. {
  183. return null;
  184. }
  185. return binaryKey;
  186. }
  187. private static byte[] TrimByteArray(byte[] array)
  188. {
  189. List<byte> trimmedArray = new List<byte>();
  190. bool startCopying = false;
  191. foreach (var item in array)
  192. {
  193. if (!startCopying)
  194. {
  195. if (item == 0x20) continue;
  196. else startCopying = true;
  197. }
  198. trimmedArray.Add(item);
  199. }
  200. array = trimmedArray.ToArray();
  201. trimmedArray = new List<byte>();
  202. for (int i = array.Length - 1; i >= 0; i--)
  203. {
  204. if (!startCopying)
  205. {
  206. if (array[i] == 0x20) continue;
  207. else startCopying = true;
  208. }
  209. trimmedArray.Add(array[i]);
  210. }
  211. return trimmedArray.ToArray().Reverse().ToArray();
  212. }
  213. private static bool StartsWith(byte[] array, byte[] containedArray)
  214. {
  215. for (int i = 0; i < array.Length; i++)
  216. {
  217. if (i == containedArray.Length) break;
  218. if (array[i] != containedArray[i]) return false;
  219. }
  220. return true;
  221. }
  222. private static bool EndsWith(byte[] array, byte[] containedArray)
  223. {
  224. for (int i = array.Length - 1, j = 0; i >= 0; i--, j++)
  225. {
  226. if (j == containedArray.Length) break;
  227. if (array[i] != containedArray[containedArray.Length - j - 1]) return false;
  228. }
  229. return true;
  230. }
  231. }
  232. }
  233. #endif