using System;
using System.IO;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Tls.Crypto;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Tls
{
public abstract class TlsDHUtilities
{
public static TlsDHConfig CreateNamedDHConfig(TlsContext context, int namedGroup)
{
if (namedGroup < 0 || NamedGroup.GetFiniteFieldBits(namedGroup) < 1)
return null;
bool padded = TlsUtilities.IsTlsV13(context);
return new TlsDHConfig(namedGroup, padded);
}
public static DHGroup GetDHGroup(TlsDHConfig dhConfig)
{
int namedGroup = dhConfig.NamedGroup;
if (namedGroup >= 0)
return GetNamedDHGroup(namedGroup);
return dhConfig.ExplicitGroup;
}
public static DHGroup GetNamedDHGroup(int namedGroup)
{
switch (namedGroup)
{
case NamedGroup.ffdhe2048:
return DHStandardGroups.rfc7919_ffdhe2048;
case NamedGroup.ffdhe3072:
return DHStandardGroups.rfc7919_ffdhe3072;
case NamedGroup.ffdhe4096:
return DHStandardGroups.rfc7919_ffdhe4096;
case NamedGroup.ffdhe6144:
return DHStandardGroups.rfc7919_ffdhe6144;
case NamedGroup.ffdhe8192:
return DHStandardGroups.rfc7919_ffdhe8192;
default:
return null;
}
}
public static int GetMinimumFiniteFieldBits(int cipherSuite)
{
/*
* NOTE: An equivalent mechanism was added to support a minimum bit-size requirement for ECC
* mooted in early drafts of RFC 8442. This requirement was removed in later drafts, so that
* mechanism is currently somewhat trivial, and this similarly so.
*/
return IsDHCipherSuite(cipherSuite) ? 1 : 0;
}
public static bool IsDHCipherSuite(int cipherSuite)
{
switch (TlsUtilities.GetKeyExchangeAlgorithm(cipherSuite))
{
case KeyExchangeAlgorithm.DH_anon:
case KeyExchangeAlgorithm.DH_DSS:
case KeyExchangeAlgorithm.DH_RSA:
case KeyExchangeAlgorithm.DHE_DSS:
case KeyExchangeAlgorithm.DHE_PSK:
case KeyExchangeAlgorithm.DHE_RSA:
return true;
default:
return false;
}
}
public static int GetNamedGroupForDHParameters(BigInteger p, BigInteger g)
{
int[] namedGroups = new int[]{ NamedGroup.ffdhe2048, NamedGroup.ffdhe3072, NamedGroup.ffdhe4096,
NamedGroup.ffdhe6144, NamedGroup.ffdhe8192 };
for (int i = 0; i < namedGroups.Length; ++i)
{
int namedGroup = namedGroups[i];
DHGroup dhGroup = GetNamedDHGroup(namedGroup);
if (dhGroup != null && dhGroup.P.Equals(p) && dhGroup.G.Equals(g))
return namedGroup;
}
return -1;
}
public static DHGroup GetStandardGroupForDHParameters(BigInteger p, BigInteger g)
{
DHGroup[] standardGroups = new DHGroup[] { DHStandardGroups.rfc7919_ffdhe2048,
DHStandardGroups.rfc7919_ffdhe3072, DHStandardGroups.rfc7919_ffdhe4096, DHStandardGroups.rfc7919_ffdhe6144,
DHStandardGroups.rfc7919_ffdhe8192, DHStandardGroups.rfc3526_1536, DHStandardGroups.rfc3526_2048,
DHStandardGroups.rfc3526_3072, DHStandardGroups.rfc3526_4096, DHStandardGroups.rfc3526_6144,
DHStandardGroups.rfc3526_8192, DHStandardGroups.rfc5996_768, DHStandardGroups.rfc5996_1024 };
for (int i = 0; i < standardGroups.Length; ++i)
{
DHGroup dhGroup = standardGroups[i];
if (dhGroup != null && dhGroup.P.Equals(p) && dhGroup.G.Equals(g))
return dhGroup;
}
return null;
}
///
public static TlsDHConfig ReceiveDHConfig(TlsContext context, TlsDHGroupVerifier dhGroupVerifier,
Stream input)
{
BigInteger p = ReadDHParameter(input);
BigInteger g = ReadDHParameter(input);
int namedGroup = GetNamedGroupForDHParameters(p, g);
if (namedGroup< 0)
{
DHGroup dhGroup = GetStandardGroupForDHParameters(p, g);
if (null == dhGroup)
{
dhGroup = new DHGroup(p, null, g, 0);
}
if (!dhGroupVerifier.Accept(dhGroup))
throw new TlsFatalAlert(AlertDescription.insufficient_security);
return new TlsDHConfig(dhGroup);
}
int[] clientSupportedGroups = context.SecurityParameters.ClientSupportedGroups;
if (null == clientSupportedGroups || Arrays.Contains(clientSupportedGroups, namedGroup))
return new TlsDHConfig(namedGroup, false);
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
///
public static BigInteger ReadDHParameter(Stream input)
{
return new BigInteger(1, TlsUtilities.ReadOpaque16(input, 1));
}
///
public static void WriteDHConfig(TlsDHConfig dhConfig, Stream output)
{
DHGroup group = GetDHGroup(dhConfig);
WriteDHParameter(group.P, output);
WriteDHParameter(group.G, output);
}
///
public static void WriteDHParameter(BigInteger x, Stream output)
{
TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
}
}
}