using System; using System.IO; using Org.BouncyCastle.Tls.Crypto; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Tls { public abstract class TlsEccUtilities { /// public static TlsECConfig CreateNamedECConfig(TlsContext context, int namedGroup) { if (NamedGroup.GetCurveBits(namedGroup) < 1) throw new TlsFatalAlert(AlertDescription.internal_error); return new TlsECConfig(namedGroup); } public static int GetMinimumCurveBits(int cipherSuite) { /* * NOTE: This mechanism was added to support a minimum bit-size requirement mooted in early * drafts of RFC 8442. This requirement was removed in later drafts, so this mechanism is * currently somewhat trivial. */ return IsEccCipherSuite(cipherSuite) ? 1 : 0; } public static bool IsEccCipherSuite(int cipherSuite) { switch (TlsUtilities.GetKeyExchangeAlgorithm(cipherSuite)) { case KeyExchangeAlgorithm.ECDH_anon: case KeyExchangeAlgorithm.ECDH_ECDSA: case KeyExchangeAlgorithm.ECDH_RSA: case KeyExchangeAlgorithm.ECDHE_ECDSA: case KeyExchangeAlgorithm.ECDHE_PSK: case KeyExchangeAlgorithm.ECDHE_RSA: return true; default: return false; } } /// public static void CheckPointEncoding(int namedGroup, byte[] encoding) { if (TlsUtilities.IsNullOrEmpty(encoding)) throw new TlsFatalAlert(AlertDescription.illegal_parameter); switch (namedGroup) { case NamedGroup.x25519: case NamedGroup.x448: return; } switch (encoding[0]) { case 0x04: // uncompressed return; case 0x00: // infinity case 0x02: // compressed case 0x03: // compressed case 0x06: // hybrid case 0x07: // hybrid default: throw new TlsFatalAlert(AlertDescription.illegal_parameter); } } /// public static TlsECConfig ReceiveECDHConfig(TlsContext context, Stream input) { short curveType = TlsUtilities.ReadUint8(input); if (curveType != ECCurveType.named_curve) throw new TlsFatalAlert(AlertDescription.handshake_failure); int namedGroup = TlsUtilities.ReadUint16(input); if (NamedGroup.RefersToAnECDHCurve(namedGroup)) { int[] clientSupportedGroups = context.SecurityParameters.ClientSupportedGroups; if (null == clientSupportedGroups || Arrays.Contains(clientSupportedGroups, namedGroup)) return new TlsECConfig(namedGroup); } throw new TlsFatalAlert(AlertDescription.illegal_parameter); } /// public static void WriteECConfig(TlsECConfig ecConfig, Stream output) { WriteNamedECParameters(ecConfig.NamedGroup, output); } /// public static void WriteNamedECParameters(int namedGroup, Stream output) { if (!NamedGroup.RefersToASpecificCurve(namedGroup)) { /* * 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(namedGroup); TlsUtilities.WriteUint16(namedGroup, output); } } }