TlsEccUtilities.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.Collections;
  4. using System.IO;
  5. using Org.BouncyCastle.Asn1.X9;
  6. using Org.BouncyCastle.Crypto;
  7. using Org.BouncyCastle.Crypto.Agreement;
  8. using Org.BouncyCastle.Crypto.EC;
  9. using Org.BouncyCastle.Crypto.Generators;
  10. using Org.BouncyCastle.Crypto.Parameters;
  11. using Org.BouncyCastle.Math;
  12. using Org.BouncyCastle.Math.EC;
  13. using Org.BouncyCastle.Math.Field;
  14. using Org.BouncyCastle.Security;
  15. using Org.BouncyCastle.Utilities;
  16. namespace Org.BouncyCastle.Crypto.Tls
  17. {
  18. public abstract class TlsEccUtilities
  19. {
  20. private static readonly string[] CurveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
  21. "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
  22. "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1",
  23. "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1",
  24. "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"};
  25. public static void AddSupportedEllipticCurvesExtension(IDictionary extensions, int[] namedCurves)
  26. {
  27. extensions[ExtensionType.elliptic_curves] = CreateSupportedEllipticCurvesExtension(namedCurves);
  28. }
  29. public static void AddSupportedPointFormatsExtension(IDictionary extensions, byte[] ecPointFormats)
  30. {
  31. extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats);
  32. }
  33. public static int[] GetSupportedEllipticCurvesExtension(IDictionary extensions)
  34. {
  35. byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.elliptic_curves);
  36. return extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData);
  37. }
  38. public static byte[] GetSupportedPointFormatsExtension(IDictionary extensions)
  39. {
  40. byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats);
  41. return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData);
  42. }
  43. public static byte[] CreateSupportedEllipticCurvesExtension(int[] namedCurves)
  44. {
  45. if (namedCurves == null || namedCurves.Length < 1)
  46. throw new TlsFatalAlert(AlertDescription.internal_error);
  47. return TlsUtilities.EncodeUint16ArrayWithUint16Length(namedCurves);
  48. }
  49. public static byte[] CreateSupportedPointFormatsExtension(byte[] ecPointFormats)
  50. {
  51. if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
  52. {
  53. /*
  54. * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
  55. * contain the value 0 (uncompressed) as one of the items in the list of point formats.
  56. */
  57. // NOTE: We add it at the end (lowest preference)
  58. ecPointFormats = Arrays.Append(ecPointFormats, ECPointFormat.uncompressed);
  59. }
  60. return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats);
  61. }
  62. public static int[] ReadSupportedEllipticCurvesExtension(byte[] extensionData)
  63. {
  64. if (extensionData == null)
  65. throw new ArgumentNullException("extensionData");
  66. MemoryStream buf = new MemoryStream(extensionData, false);
  67. int length = TlsUtilities.ReadUint16(buf);
  68. if (length < 2 || (length & 1) != 0)
  69. throw new TlsFatalAlert(AlertDescription.decode_error);
  70. int[] namedCurves = TlsUtilities.ReadUint16Array(length / 2, buf);
  71. TlsProtocol.AssertEmpty(buf);
  72. return namedCurves;
  73. }
  74. public static byte[] ReadSupportedPointFormatsExtension(byte[] extensionData)
  75. {
  76. if (extensionData == null)
  77. throw new ArgumentNullException("extensionData");
  78. MemoryStream buf = new MemoryStream(extensionData, false);
  79. byte length = TlsUtilities.ReadUint8(buf);
  80. if (length < 1)
  81. throw new TlsFatalAlert(AlertDescription.decode_error);
  82. byte[] ecPointFormats = TlsUtilities.ReadUint8Array(length, buf);
  83. TlsProtocol.AssertEmpty(buf);
  84. if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
  85. {
  86. /*
  87. * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
  88. * contain the value 0 (uncompressed) as one of the items in the list of point formats.
  89. */
  90. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  91. }
  92. return ecPointFormats;
  93. }
  94. public static string GetNameOfNamedCurve(int namedCurve)
  95. {
  96. return IsSupportedNamedCurve(namedCurve) ? CurveNames[namedCurve - 1] : null;
  97. }
  98. public static ECDomainParameters GetParametersForNamedCurve(int namedCurve)
  99. {
  100. string curveName = GetNameOfNamedCurve(namedCurve);
  101. if (curveName == null)
  102. return null;
  103. // Parameters are lazily created the first time a particular curve is accessed
  104. X9ECParameters ecP = CustomNamedCurves.GetByName(curveName);
  105. if (ecP == null)
  106. {
  107. ecP = ECNamedCurveTable.GetByName(curveName);
  108. if (ecP == null)
  109. return null;
  110. }
  111. // It's a bit inefficient to do this conversion every time
  112. return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
  113. }
  114. public static bool HasAnySupportedNamedCurves()
  115. {
  116. return CurveNames.Length > 0;
  117. }
  118. public static bool ContainsEccCipherSuites(int[] cipherSuites)
  119. {
  120. for (int i = 0; i < cipherSuites.Length; ++i)
  121. {
  122. if (IsEccCipherSuite(cipherSuites[i]))
  123. return true;
  124. }
  125. return false;
  126. }
  127. public static bool IsEccCipherSuite(int cipherSuite)
  128. {
  129. switch (cipherSuite)
  130. {
  131. /*
  132. * RFC 4492
  133. */
  134. case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
  135. case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
  136. case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
  137. case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
  138. case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
  139. case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
  140. case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
  141. case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
  142. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
  143. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
  144. case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
  145. case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
  146. case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
  147. case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
  148. case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
  149. case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
  150. case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
  151. case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
  152. case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
  153. case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
  154. case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
  155. case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
  156. case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
  157. case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
  158. case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
  159. /*
  160. * RFC 5289
  161. */
  162. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
  163. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
  164. case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
  165. case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
  166. case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
  167. case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
  168. case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
  169. case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
  170. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
  171. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
  172. case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
  173. case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
  174. case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
  175. case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
  176. case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
  177. case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
  178. /*
  179. * RFC 5489
  180. */
  181. case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
  182. case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
  183. case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
  184. case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
  185. case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
  186. case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
  187. case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
  188. case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
  189. case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
  190. /*
  191. * RFC 6367
  192. */
  193. case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
  194. case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
  195. case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
  196. case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
  197. case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
  198. case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
  199. case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
  200. case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
  201. case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
  202. case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
  203. case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
  204. case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
  205. case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
  206. case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
  207. case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
  208. case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
  209. case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
  210. case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
  211. /*
  212. * RFC 7251
  213. */
  214. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
  215. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
  216. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
  217. case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
  218. /*
  219. * draft-ietf-tls-chacha20-poly1305-04
  220. */
  221. case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
  222. case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
  223. case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
  224. /*
  225. * draft-zauner-tls-aes-ocb-04
  226. */
  227. case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
  228. case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
  229. case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
  230. case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
  231. case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
  232. case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
  233. return true;
  234. default:
  235. return false;
  236. }
  237. }
  238. public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
  239. {
  240. return a != null && a.Equals(b);
  241. }
  242. public static bool IsSupportedNamedCurve(int namedCurve)
  243. {
  244. return (namedCurve > 0 && namedCurve <= CurveNames.Length);
  245. }
  246. public static bool IsCompressionPreferred(byte[] ecPointFormats, byte compressionFormat)
  247. {
  248. if (ecPointFormats == null)
  249. return false;
  250. for (int i = 0; i < ecPointFormats.Length; ++i)
  251. {
  252. byte ecPointFormat = ecPointFormats[i];
  253. if (ecPointFormat == ECPointFormat.uncompressed)
  254. return false;
  255. if (ecPointFormat == compressionFormat)
  256. return true;
  257. }
  258. return false;
  259. }
  260. public static byte[] SerializeECFieldElement(int fieldSize, BigInteger x)
  261. {
  262. return BigIntegers.AsUnsignedByteArray((fieldSize + 7) / 8, x);
  263. }
  264. public static byte[] SerializeECPoint(byte[] ecPointFormats, ECPoint point)
  265. {
  266. ECCurve curve = point.Curve;
  267. /*
  268. * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format. Here, the
  269. * format MUST conform to what the server has requested through a Supported Point Formats
  270. * Extension if this extension was used, and MUST be uncompressed if this extension was not
  271. * used.
  272. */
  273. bool compressed = false;
  274. if (ECAlgorithms.IsFpCurve(curve))
  275. {
  276. compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_prime);
  277. }
  278. else if (ECAlgorithms.IsF2mCurve(curve))
  279. {
  280. compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_char2);
  281. }
  282. return point.GetEncoded(compressed);
  283. }
  284. public static byte[] SerializeECPublicKey(byte[] ecPointFormats, ECPublicKeyParameters keyParameters)
  285. {
  286. return SerializeECPoint(ecPointFormats, keyParameters.Q);
  287. }
  288. public static BigInteger DeserializeECFieldElement(int fieldSize, byte[] encoding)
  289. {
  290. int requiredLength = (fieldSize + 7) / 8;
  291. if (encoding.Length != requiredLength)
  292. throw new TlsFatalAlert(AlertDescription.decode_error);
  293. return new BigInteger(1, encoding);
  294. }
  295. public static ECPoint DeserializeECPoint(byte[] ecPointFormats, ECCurve curve, byte[] encoding)
  296. {
  297. if (encoding == null || encoding.Length < 1)
  298. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  299. byte actualFormat;
  300. switch (encoding[0])
  301. {
  302. case 0x02: // compressed
  303. case 0x03: // compressed
  304. {
  305. if (ECAlgorithms.IsF2mCurve(curve))
  306. {
  307. actualFormat = ECPointFormat.ansiX962_compressed_char2;
  308. }
  309. else if (ECAlgorithms.IsFpCurve(curve))
  310. {
  311. actualFormat = ECPointFormat.ansiX962_compressed_prime;
  312. }
  313. else
  314. {
  315. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  316. }
  317. break;
  318. }
  319. case 0x04: // uncompressed
  320. {
  321. actualFormat = ECPointFormat.uncompressed;
  322. break;
  323. }
  324. case 0x00: // infinity
  325. case 0x06: // hybrid
  326. case 0x07: // hybrid
  327. default:
  328. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  329. }
  330. if (actualFormat != ECPointFormat.uncompressed
  331. && (ecPointFormats == null || !Arrays.Contains(ecPointFormats, actualFormat)))
  332. {
  333. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  334. }
  335. return curve.DecodePoint(encoding);
  336. }
  337. public static ECPublicKeyParameters DeserializeECPublicKey(byte[] ecPointFormats, ECDomainParameters curve_params,
  338. byte[] encoding)
  339. {
  340. try
  341. {
  342. ECPoint Y = DeserializeECPoint(ecPointFormats, curve_params.Curve, encoding);
  343. return new ECPublicKeyParameters(Y, curve_params);
  344. }
  345. catch (Exception e)
  346. {
  347. throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
  348. }
  349. }
  350. public static byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey)
  351. {
  352. ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
  353. basicAgreement.Init(privateKey);
  354. BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
  355. /*
  356. * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
  357. * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
  358. * any given field; leading zeros found in this octet string MUST NOT be truncated.
  359. */
  360. return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
  361. }
  362. public static AsymmetricCipherKeyPair GenerateECKeyPair(SecureRandom random, ECDomainParameters ecParams)
  363. {
  364. ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
  365. keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random));
  366. return keyPairGenerator.GenerateKeyPair();
  367. }
  368. public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
  369. ECDomainParameters ecParams, Stream output)
  370. {
  371. AsymmetricCipherKeyPair kp = GenerateECKeyPair(random, ecParams);
  372. ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
  373. WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
  374. return (ECPrivateKeyParameters)kp.Private;
  375. }
  376. // TODO Refactor around ServerECDHParams before making this public
  377. internal static ECPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random, int[] namedCurves,
  378. byte[] ecPointFormats, Stream output)
  379. {
  380. /* First we try to find a supported named curve from the client's list. */
  381. int namedCurve = -1;
  382. if (namedCurves == null)
  383. {
  384. // TODO Let the peer choose the default named curve
  385. namedCurve = NamedCurve.secp256r1;
  386. }
  387. else
  388. {
  389. for (int i = 0; i < namedCurves.Length; ++i)
  390. {
  391. int entry = namedCurves[i];
  392. if (NamedCurve.IsValid(entry) && IsSupportedNamedCurve(entry))
  393. {
  394. namedCurve = entry;
  395. break;
  396. }
  397. }
  398. }
  399. ECDomainParameters ecParams = null;
  400. if (namedCurve >= 0)
  401. {
  402. ecParams = GetParametersForNamedCurve(namedCurve);
  403. }
  404. else
  405. {
  406. /* If no named curves are suitable, check if the client supports explicit curves. */
  407. if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_prime_curves))
  408. {
  409. ecParams = GetParametersForNamedCurve(NamedCurve.secp256r1);
  410. }
  411. else if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_char2_curves))
  412. {
  413. ecParams = GetParametersForNamedCurve(NamedCurve.sect283r1);
  414. }
  415. }
  416. if (ecParams == null)
  417. {
  418. /*
  419. * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
  420. * a suitable curve.
  421. */
  422. throw new TlsFatalAlert(AlertDescription.internal_error);
  423. }
  424. if (namedCurve < 0)
  425. {
  426. WriteExplicitECParameters(ecPointFormats, ecParams, output);
  427. }
  428. else
  429. {
  430. WriteNamedECParameters(namedCurve, output);
  431. }
  432. return GenerateEphemeralClientKeyExchange(random, ecPointFormats, ecParams, output);
  433. }
  434. public static ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
  435. {
  436. // TODO Check RFC 4492 for validation
  437. return key;
  438. }
  439. public static int ReadECExponent(int fieldSize, Stream input)
  440. {
  441. BigInteger K = ReadECParameter(input);
  442. if (K.BitLength < 32)
  443. {
  444. int k = K.IntValue;
  445. if (k > 0 && k < fieldSize)
  446. {
  447. return k;
  448. }
  449. }
  450. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  451. }
  452. public static BigInteger ReadECFieldElement(int fieldSize, Stream input)
  453. {
  454. return DeserializeECFieldElement(fieldSize, TlsUtilities.ReadOpaque8(input));
  455. }
  456. public static BigInteger ReadECParameter(Stream input)
  457. {
  458. // TODO Are leading zeroes okay here?
  459. return new BigInteger(1, TlsUtilities.ReadOpaque8(input));
  460. }
  461. public static ECDomainParameters ReadECParameters(int[] namedCurves, byte[] ecPointFormats, Stream input)
  462. {
  463. try
  464. {
  465. byte curveType = TlsUtilities.ReadUint8(input);
  466. switch (curveType)
  467. {
  468. case ECCurveType.explicit_prime:
  469. {
  470. CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_prime_curves);
  471. BigInteger prime_p = ReadECParameter(input);
  472. BigInteger a = ReadECFieldElement(prime_p.BitLength, input);
  473. BigInteger b = ReadECFieldElement(prime_p.BitLength, input);
  474. byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
  475. BigInteger order = ReadECParameter(input);
  476. BigInteger cofactor = ReadECParameter(input);
  477. ECCurve curve = new FpCurve(prime_p, a, b, order, cofactor);
  478. ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
  479. return new ECDomainParameters(curve, basePoint, order, cofactor);
  480. }
  481. case ECCurveType.explicit_char2:
  482. {
  483. CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_char2_curves);
  484. int m = TlsUtilities.ReadUint16(input);
  485. byte basis = TlsUtilities.ReadUint8(input);
  486. if (!ECBasisType.IsValid(basis))
  487. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  488. int k1 = ReadECExponent(m, input), k2 = -1, k3 = -1;
  489. if (basis == ECBasisType.ec_basis_pentanomial)
  490. {
  491. k2 = ReadECExponent(m, input);
  492. k3 = ReadECExponent(m, input);
  493. }
  494. BigInteger a = ReadECFieldElement(m, input);
  495. BigInteger b = ReadECFieldElement(m, input);
  496. byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
  497. BigInteger order = ReadECParameter(input);
  498. BigInteger cofactor = ReadECParameter(input);
  499. ECCurve curve = (basis == ECBasisType.ec_basis_pentanomial)
  500. ? new F2mCurve(m, k1, k2, k3, a, b, order, cofactor)
  501. : new F2mCurve(m, k1, a, b, order, cofactor);
  502. ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
  503. return new ECDomainParameters(curve, basePoint, order, cofactor);
  504. }
  505. case ECCurveType.named_curve:
  506. {
  507. int namedCurve = TlsUtilities.ReadUint16(input);
  508. if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
  509. {
  510. /*
  511. * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a
  512. * specific curve. Values of NamedCurve that indicate support for a class of
  513. * explicitly defined curves are not allowed here [...].
  514. */
  515. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  516. }
  517. CheckNamedCurve(namedCurves, namedCurve);
  518. return GetParametersForNamedCurve(namedCurve);
  519. }
  520. default:
  521. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  522. }
  523. }
  524. catch (Exception e)
  525. {
  526. throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
  527. }
  528. }
  529. private static void CheckNamedCurve(int[] namedCurves, int namedCurve)
  530. {
  531. if (namedCurves != null && !Arrays.Contains(namedCurves, namedCurve))
  532. {
  533. /*
  534. * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite
  535. * unless they can complete the handshake while respecting the choice of curves
  536. * and compression techniques specified by the client.
  537. */
  538. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  539. }
  540. }
  541. public static void WriteECExponent(int k, Stream output)
  542. {
  543. BigInteger K = BigInteger.ValueOf(k);
  544. WriteECParameter(K, output);
  545. }
  546. public static void WriteECFieldElement(ECFieldElement x, Stream output)
  547. {
  548. TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
  549. }
  550. public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
  551. {
  552. TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
  553. }
  554. public static void WriteECParameter(BigInteger x, Stream output)
  555. {
  556. TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
  557. }
  558. public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
  559. Stream output)
  560. {
  561. ECCurve curve = ecParameters.Curve;
  562. if (ECAlgorithms.IsFpCurve(curve))
  563. {
  564. TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);
  565. WriteECParameter(curve.Field.Characteristic, output);
  566. }
  567. else if (ECAlgorithms.IsF2mCurve(curve))
  568. {
  569. IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
  570. int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
  571. TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);
  572. int m = exponents[exponents.Length - 1];
  573. TlsUtilities.CheckUint16(m);
  574. TlsUtilities.WriteUint16(m, output);
  575. if (exponents.Length == 3)
  576. {
  577. TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
  578. WriteECExponent(exponents[1], output);
  579. }
  580. else if (exponents.Length == 5)
  581. {
  582. TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
  583. WriteECExponent(exponents[1], output);
  584. WriteECExponent(exponents[2], output);
  585. WriteECExponent(exponents[3], output);
  586. }
  587. else
  588. {
  589. throw new ArgumentException("Only trinomial and pentomial curves are supported");
  590. }
  591. }
  592. else
  593. {
  594. throw new ArgumentException("'ecParameters' not a known curve type");
  595. }
  596. WriteECFieldElement(curve.A, output);
  597. WriteECFieldElement(curve.B, output);
  598. TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
  599. WriteECParameter(ecParameters.N, output);
  600. WriteECParameter(ecParameters.H, output);
  601. }
  602. public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
  603. {
  604. TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
  605. }
  606. public static void WriteNamedECParameters(int namedCurve, Stream output)
  607. {
  608. if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
  609. {
  610. /*
  611. * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific
  612. * curve. Values of NamedCurve that indicate support for a class of explicitly defined
  613. * curves are not allowed here [...].
  614. */
  615. throw new TlsFatalAlert(AlertDescription.internal_error);
  616. }
  617. TlsUtilities.WriteUint8(ECCurveType.named_curve, output);
  618. TlsUtilities.CheckUint16(namedCurve);
  619. TlsUtilities.WriteUint16(namedCurve, output);
  620. }
  621. }
  622. }
  623. #endif