123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.Collections;
- using System.IO;
- using Org.BouncyCastle.Asn1.X9;
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Crypto.Agreement;
- using Org.BouncyCastle.Crypto.EC;
- using Org.BouncyCastle.Crypto.Generators;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Math;
- using Org.BouncyCastle.Math.EC;
- using Org.BouncyCastle.Math.Field;
- using Org.BouncyCastle.Security;
- using Org.BouncyCastle.Utilities;
- namespace Org.BouncyCastle.Crypto.Tls
- {
- public abstract class TlsEccUtilities
- {
- private static readonly string[] CurveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
- "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
- "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1",
- "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1",
- "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"};
- public static void AddSupportedEllipticCurvesExtension(IDictionary extensions, int[] namedCurves)
- {
- extensions[ExtensionType.elliptic_curves] = CreateSupportedEllipticCurvesExtension(namedCurves);
- }
- public static void AddSupportedPointFormatsExtension(IDictionary extensions, byte[] ecPointFormats)
- {
- extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats);
- }
- public static int[] GetSupportedEllipticCurvesExtension(IDictionary extensions)
- {
- byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.elliptic_curves);
- return extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData);
- }
- public static byte[] GetSupportedPointFormatsExtension(IDictionary extensions)
- {
- byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats);
- return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData);
- }
- public static byte[] CreateSupportedEllipticCurvesExtension(int[] namedCurves)
- {
- if (namedCurves == null || namedCurves.Length < 1)
- throw new TlsFatalAlert(AlertDescription.internal_error);
- return TlsUtilities.EncodeUint16ArrayWithUint16Length(namedCurves);
- }
- public static byte[] CreateSupportedPointFormatsExtension(byte[] ecPointFormats)
- {
- if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
- {
- /*
- * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
- * contain the value 0 (uncompressed) as one of the items in the list of point formats.
- */
- // NOTE: We add it at the end (lowest preference)
- ecPointFormats = Arrays.Append(ecPointFormats, ECPointFormat.uncompressed);
- }
- return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats);
- }
- public static int[] ReadSupportedEllipticCurvesExtension(byte[] extensionData)
- {
- if (extensionData == null)
- throw new ArgumentNullException("extensionData");
- MemoryStream buf = new MemoryStream(extensionData, false);
- int length = TlsUtilities.ReadUint16(buf);
- if (length < 2 || (length & 1) != 0)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- int[] namedCurves = TlsUtilities.ReadUint16Array(length / 2, buf);
- TlsProtocol.AssertEmpty(buf);
- return namedCurves;
- }
- public static byte[] ReadSupportedPointFormatsExtension(byte[] extensionData)
- {
- if (extensionData == null)
- throw new ArgumentNullException("extensionData");
- MemoryStream buf = new MemoryStream(extensionData, false);
- byte length = TlsUtilities.ReadUint8(buf);
- if (length < 1)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- byte[] ecPointFormats = TlsUtilities.ReadUint8Array(length, buf);
- TlsProtocol.AssertEmpty(buf);
- if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
- {
- /*
- * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
- * contain the value 0 (uncompressed) as one of the items in the list of point formats.
- */
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- return ecPointFormats;
- }
- public static string GetNameOfNamedCurve(int namedCurve)
- {
- return IsSupportedNamedCurve(namedCurve) ? CurveNames[namedCurve - 1] : null;
- }
- public static ECDomainParameters GetParametersForNamedCurve(int namedCurve)
- {
- string curveName = GetNameOfNamedCurve(namedCurve);
- if (curveName == null)
- return null;
- // Parameters are lazily created the first time a particular curve is accessed
- X9ECParameters ecP = CustomNamedCurves.GetByName(curveName);
- if (ecP == null)
- {
- ecP = ECNamedCurveTable.GetByName(curveName);
- if (ecP == null)
- return null;
- }
- // It's a bit inefficient to do this conversion every time
- return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
- }
- public static bool HasAnySupportedNamedCurves()
- {
- return CurveNames.Length > 0;
- }
- public static bool ContainsEccCipherSuites(int[] cipherSuites)
- {
- for (int i = 0; i < cipherSuites.Length; ++i)
- {
- if (IsEccCipherSuite(cipherSuites[i]))
- return true;
- }
- return false;
- }
- public static bool IsEccCipherSuite(int cipherSuite)
- {
- switch (cipherSuite)
- {
- /*
- * RFC 4492
- */
- case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
- case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
- /*
- * RFC 5289
- */
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
- /*
- * RFC 5489
- */
- case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
- case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
- case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
- /*
- * RFC 6367
- */
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
- case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
- case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
- case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
- /*
- * RFC 7251
- */
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
- case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
- /*
- * draft-ietf-tls-chacha20-poly1305-04
- */
- case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
- case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- /*
- * draft-zauner-tls-aes-ocb-04
- */
- case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
- case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
- return true;
- default:
- return false;
- }
- }
- public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
- {
- return a != null && a.Equals(b);
- }
- public static bool IsSupportedNamedCurve(int namedCurve)
- {
- return (namedCurve > 0 && namedCurve <= CurveNames.Length);
- }
- public static bool IsCompressionPreferred(byte[] ecPointFormats, byte compressionFormat)
- {
- if (ecPointFormats == null)
- return false;
- for (int i = 0; i < ecPointFormats.Length; ++i)
- {
- byte ecPointFormat = ecPointFormats[i];
- if (ecPointFormat == ECPointFormat.uncompressed)
- return false;
- if (ecPointFormat == compressionFormat)
- return true;
- }
- return false;
- }
- public static byte[] SerializeECFieldElement(int fieldSize, BigInteger x)
- {
- return BigIntegers.AsUnsignedByteArray((fieldSize + 7) / 8, x);
- }
- public static byte[] SerializeECPoint(byte[] ecPointFormats, ECPoint point)
- {
- ECCurve curve = point.Curve;
- /*
- * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format. Here, the
- * format MUST conform to what the server has requested through a Supported Point Formats
- * Extension if this extension was used, and MUST be uncompressed if this extension was not
- * used.
- */
- bool compressed = false;
- if (ECAlgorithms.IsFpCurve(curve))
- {
- compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_prime);
- }
- else if (ECAlgorithms.IsF2mCurve(curve))
- {
- compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_char2);
- }
- return point.GetEncoded(compressed);
- }
- public static byte[] SerializeECPublicKey(byte[] ecPointFormats, ECPublicKeyParameters keyParameters)
- {
- return SerializeECPoint(ecPointFormats, keyParameters.Q);
- }
- public static BigInteger DeserializeECFieldElement(int fieldSize, byte[] encoding)
- {
- int requiredLength = (fieldSize + 7) / 8;
- if (encoding.Length != requiredLength)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- return new BigInteger(1, encoding);
- }
- public static ECPoint DeserializeECPoint(byte[] ecPointFormats, ECCurve curve, byte[] encoding)
- {
- if (encoding == null || encoding.Length < 1)
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- byte actualFormat;
- switch (encoding[0])
- {
- case 0x02: // compressed
- case 0x03: // compressed
- {
- if (ECAlgorithms.IsF2mCurve(curve))
- {
- actualFormat = ECPointFormat.ansiX962_compressed_char2;
- }
- else if (ECAlgorithms.IsFpCurve(curve))
- {
- actualFormat = ECPointFormat.ansiX962_compressed_prime;
- }
- else
- {
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- break;
- }
- case 0x04: // uncompressed
- {
- actualFormat = ECPointFormat.uncompressed;
- break;
- }
- case 0x00: // infinity
- case 0x06: // hybrid
- case 0x07: // hybrid
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- if (actualFormat != ECPointFormat.uncompressed
- && (ecPointFormats == null || !Arrays.Contains(ecPointFormats, actualFormat)))
- {
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- return curve.DecodePoint(encoding);
- }
- public static ECPublicKeyParameters DeserializeECPublicKey(byte[] ecPointFormats, ECDomainParameters curve_params,
- byte[] encoding)
- {
- try
- {
- ECPoint Y = DeserializeECPoint(ecPointFormats, curve_params.Curve, encoding);
- return new ECPublicKeyParameters(Y, curve_params);
- }
- catch (Exception e)
- {
- throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
- }
- }
- public static byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey)
- {
- ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
- basicAgreement.Init(privateKey);
- BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
- /*
- * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
- * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
- * any given field; leading zeros found in this octet string MUST NOT be truncated.
- */
- return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
- }
- public static AsymmetricCipherKeyPair GenerateECKeyPair(SecureRandom random, ECDomainParameters ecParams)
- {
- ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
- keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random));
- return keyPairGenerator.GenerateKeyPair();
- }
- public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
- ECDomainParameters ecParams, Stream output)
- {
- AsymmetricCipherKeyPair kp = GenerateECKeyPair(random, ecParams);
- ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
- WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
- return (ECPrivateKeyParameters)kp.Private;
- }
- // TODO Refactor around ServerECDHParams before making this public
- internal static ECPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random, int[] namedCurves,
- byte[] ecPointFormats, Stream output)
- {
- /* First we try to find a supported named curve from the client's list. */
- int namedCurve = -1;
- if (namedCurves == null)
- {
- // TODO Let the peer choose the default named curve
- namedCurve = NamedCurve.secp256r1;
- }
- else
- {
- for (int i = 0; i < namedCurves.Length; ++i)
- {
- int entry = namedCurves[i];
- if (NamedCurve.IsValid(entry) && IsSupportedNamedCurve(entry))
- {
- namedCurve = entry;
- break;
- }
- }
- }
- ECDomainParameters ecParams = null;
- if (namedCurve >= 0)
- {
- ecParams = GetParametersForNamedCurve(namedCurve);
- }
- else
- {
- /* If no named curves are suitable, check if the client supports explicit curves. */
- if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_prime_curves))
- {
- ecParams = GetParametersForNamedCurve(NamedCurve.secp256r1);
- }
- else if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_char2_curves))
- {
- ecParams = GetParametersForNamedCurve(NamedCurve.sect283r1);
- }
- }
- if (ecParams == null)
- {
- /*
- * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
- * a suitable curve.
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- if (namedCurve < 0)
- {
- WriteExplicitECParameters(ecPointFormats, ecParams, output);
- }
- else
- {
- WriteNamedECParameters(namedCurve, output);
- }
- return GenerateEphemeralClientKeyExchange(random, ecPointFormats, ecParams, output);
- }
- public static ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
- {
- // TODO Check RFC 4492 for validation
- return key;
- }
- public static int ReadECExponent(int fieldSize, Stream input)
- {
- BigInteger K = ReadECParameter(input);
- if (K.BitLength < 32)
- {
- int k = K.IntValue;
- if (k > 0 && k < fieldSize)
- {
- return k;
- }
- }
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- public static BigInteger ReadECFieldElement(int fieldSize, Stream input)
- {
- return DeserializeECFieldElement(fieldSize, TlsUtilities.ReadOpaque8(input));
- }
- public static BigInteger ReadECParameter(Stream input)
- {
- // TODO Are leading zeroes okay here?
- return new BigInteger(1, TlsUtilities.ReadOpaque8(input));
- }
- public static ECDomainParameters ReadECParameters(int[] namedCurves, byte[] ecPointFormats, Stream input)
- {
- try
- {
- byte curveType = TlsUtilities.ReadUint8(input);
- switch (curveType)
- {
- case ECCurveType.explicit_prime:
- {
- CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_prime_curves);
- BigInteger prime_p = ReadECParameter(input);
- BigInteger a = ReadECFieldElement(prime_p.BitLength, input);
- BigInteger b = ReadECFieldElement(prime_p.BitLength, input);
- byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
- BigInteger order = ReadECParameter(input);
- BigInteger cofactor = ReadECParameter(input);
- ECCurve curve = new FpCurve(prime_p, a, b, order, cofactor);
- ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
- return new ECDomainParameters(curve, basePoint, order, cofactor);
- }
- case ECCurveType.explicit_char2:
- {
- CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_char2_curves);
- int m = TlsUtilities.ReadUint16(input);
- byte basis = TlsUtilities.ReadUint8(input);
- if (!ECBasisType.IsValid(basis))
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- int k1 = ReadECExponent(m, input), k2 = -1, k3 = -1;
- if (basis == ECBasisType.ec_basis_pentanomial)
- {
- k2 = ReadECExponent(m, input);
- k3 = ReadECExponent(m, input);
- }
- BigInteger a = ReadECFieldElement(m, input);
- BigInteger b = ReadECFieldElement(m, input);
- byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
- BigInteger order = ReadECParameter(input);
- BigInteger cofactor = ReadECParameter(input);
- ECCurve curve = (basis == ECBasisType.ec_basis_pentanomial)
- ? new F2mCurve(m, k1, k2, k3, a, b, order, cofactor)
- : new F2mCurve(m, k1, a, b, order, cofactor);
- ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
- return new ECDomainParameters(curve, basePoint, order, cofactor);
- }
- case ECCurveType.named_curve:
- {
- int namedCurve = TlsUtilities.ReadUint16(input);
- if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
- {
- /*
- * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a
- * specific curve. Values of NamedCurve that indicate support for a class of
- * explicitly defined curves are not allowed here [...].
- */
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- CheckNamedCurve(namedCurves, namedCurve);
- return GetParametersForNamedCurve(namedCurve);
- }
- default:
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- }
- catch (Exception e)
- {
- throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
- }
- }
- private static void CheckNamedCurve(int[] namedCurves, int namedCurve)
- {
- if (namedCurves != null && !Arrays.Contains(namedCurves, namedCurve))
- {
- /*
- * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite
- * unless they can complete the handshake while respecting the choice of curves
- * and compression techniques specified by the client.
- */
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- }
- }
- public static void WriteECExponent(int k, Stream output)
- {
- BigInteger K = BigInteger.ValueOf(k);
- WriteECParameter(K, output);
- }
- public static void WriteECFieldElement(ECFieldElement x, Stream output)
- {
- TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
- }
- public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
- {
- TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
- }
- public static void WriteECParameter(BigInteger x, Stream output)
- {
- TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
- }
- public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
- Stream output)
- {
- ECCurve curve = ecParameters.Curve;
- if (ECAlgorithms.IsFpCurve(curve))
- {
- TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);
- WriteECParameter(curve.Field.Characteristic, output);
- }
- else if (ECAlgorithms.IsF2mCurve(curve))
- {
- IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
- int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
- TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);
- int m = exponents[exponents.Length - 1];
- TlsUtilities.CheckUint16(m);
- TlsUtilities.WriteUint16(m, output);
- if (exponents.Length == 3)
- {
- TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
- WriteECExponent(exponents[1], output);
- }
- else if (exponents.Length == 5)
- {
- TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
- WriteECExponent(exponents[1], output);
- WriteECExponent(exponents[2], output);
- WriteECExponent(exponents[3], output);
- }
- else
- {
- throw new ArgumentException("Only trinomial and pentomial curves are supported");
- }
- }
- else
- {
- throw new ArgumentException("'ecParameters' not a known curve type");
- }
- WriteECFieldElement(curve.A, output);
- WriteECFieldElement(curve.B, output);
- TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
- WriteECParameter(ecParameters.N, output);
- WriteECParameter(ecParameters.H, output);
- }
- public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
- {
- TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
- }
- public static void WriteNamedECParameters(int namedCurve, Stream output)
- {
- if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
- {
- /*
- * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific
- * curve. Values of NamedCurve that indicate support for a class of explicitly defined
- * curves are not allowed here [...].
- */
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- TlsUtilities.WriteUint8(ECCurveType.named_curve, output);
- TlsUtilities.CheckUint16(namedCurve);
- TlsUtilities.WriteUint16(namedCurve, output);
- }
- }
- }
- #endif
|