1 package org.bouncycastle.tls; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.math.BigInteger; 7 8 import org.bouncycastle.tls.crypto.DHGroup; 9 import org.bouncycastle.tls.crypto.DHStandardGroups; 10 import org.bouncycastle.tls.crypto.TlsDHConfig; 11 import org.bouncycastle.util.Arrays; 12 import org.bouncycastle.util.BigIntegers; 13 14 public class TlsDHUtils 15 { createNamedDHConfig(TlsContext context, int namedGroup)16 public static TlsDHConfig createNamedDHConfig(TlsContext context, int namedGroup) 17 { 18 if (namedGroup < 0 || NamedGroup.getFiniteFieldBits(namedGroup) < 1) 19 { 20 return null; 21 } 22 23 boolean padded = TlsUtils.isTLSv13(context); 24 return new TlsDHConfig(namedGroup, padded); 25 } 26 getDHGroup(TlsDHConfig dhConfig)27 public static DHGroup getDHGroup(TlsDHConfig dhConfig) 28 { 29 int namedGroup = dhConfig.getNamedGroup(); 30 if (namedGroup >= 0) 31 { 32 return getNamedDHGroup(namedGroup); 33 } 34 35 return dhConfig.getExplicitGroup(); 36 } 37 getNamedDHGroup(int namedGroup)38 public static DHGroup getNamedDHGroup(int namedGroup) 39 { 40 switch (namedGroup) 41 { 42 case NamedGroup.ffdhe2048: 43 return DHStandardGroups.rfc7919_ffdhe2048; 44 case NamedGroup.ffdhe3072: 45 return DHStandardGroups.rfc7919_ffdhe3072; 46 case NamedGroup.ffdhe4096: 47 return DHStandardGroups.rfc7919_ffdhe4096; 48 case NamedGroup.ffdhe6144: 49 return DHStandardGroups.rfc7919_ffdhe6144; 50 case NamedGroup.ffdhe8192: 51 return DHStandardGroups.rfc7919_ffdhe8192; 52 default: 53 return null; 54 } 55 } 56 getMinimumFiniteFieldBits(int cipherSuite)57 public static int getMinimumFiniteFieldBits(int cipherSuite) 58 { 59 /* 60 * NOTE: An equivalent mechanism was added to support a minimum bit-size requirement for ECC 61 * mooted in early drafts of RFC 8442. This requirement was removed in later drafts, so that 62 * mechanism is currently somewhat trivial, and this similarly so. 63 */ 64 return isDHCipherSuite(cipherSuite) ? 1 : 0; 65 } 66 isDHCipherSuite(int cipherSuite)67 public static boolean isDHCipherSuite(int cipherSuite) 68 { 69 switch (TlsUtils.getKeyExchangeAlgorithm(cipherSuite)) 70 { 71 case KeyExchangeAlgorithm.DH_anon: 72 case KeyExchangeAlgorithm.DH_DSS: 73 case KeyExchangeAlgorithm.DH_RSA: 74 case KeyExchangeAlgorithm.DHE_DSS: 75 case KeyExchangeAlgorithm.DHE_PSK: 76 case KeyExchangeAlgorithm.DHE_RSA: 77 return true; 78 79 default: 80 return false; 81 } 82 } 83 getNamedGroupForDHParameters(BigInteger p, BigInteger g)84 public static int getNamedGroupForDHParameters(BigInteger p, BigInteger g) 85 { 86 int[] namedGroups = new int[]{ NamedGroup.ffdhe2048, NamedGroup.ffdhe3072, NamedGroup.ffdhe4096, 87 NamedGroup.ffdhe6144, NamedGroup.ffdhe8192 }; 88 89 for (int i = 0; i < namedGroups.length; ++i) 90 { 91 int namedGroup = namedGroups[i]; 92 DHGroup dhGroup = getNamedDHGroup(namedGroup); 93 if (dhGroup != null && dhGroup.getP().equals(p) && dhGroup.getG().equals(g)) 94 { 95 return namedGroup; 96 } 97 } 98 99 return -1; 100 } 101 getStandardGroupForDHParameters(BigInteger p, BigInteger g)102 public static DHGroup getStandardGroupForDHParameters(BigInteger p, BigInteger g) 103 { 104 DHGroup[] standardGroups = new DHGroup[] { DHStandardGroups.rfc7919_ffdhe2048, 105 DHStandardGroups.rfc7919_ffdhe3072, DHStandardGroups.rfc7919_ffdhe4096, DHStandardGroups.rfc7919_ffdhe6144, 106 DHStandardGroups.rfc7919_ffdhe8192, DHStandardGroups.rfc3526_1536, DHStandardGroups.rfc3526_2048, 107 DHStandardGroups.rfc3526_3072, DHStandardGroups.rfc3526_4096, DHStandardGroups.rfc3526_6144, 108 DHStandardGroups.rfc3526_8192, DHStandardGroups.rfc5996_768, DHStandardGroups.rfc5996_1024 }; 109 110 for (int i = 0; i < standardGroups.length; ++i) 111 { 112 DHGroup dhGroup = standardGroups[i]; 113 if (dhGroup != null && dhGroup.getP().equals(p) && dhGroup.getG().equals(g)) 114 { 115 return dhGroup; 116 } 117 } 118 119 return null; 120 } 121 receiveDHConfig(TlsContext context, TlsDHGroupVerifier dhGroupVerifier, InputStream input)122 public static TlsDHConfig receiveDHConfig(TlsContext context, TlsDHGroupVerifier dhGroupVerifier, 123 InputStream input) throws IOException 124 { 125 BigInteger p = readDHParameter(input); 126 BigInteger g = readDHParameter(input); 127 128 int namedGroup = getNamedGroupForDHParameters(p, g); 129 if (namedGroup < 0) 130 { 131 DHGroup dhGroup = getStandardGroupForDHParameters(p, g); 132 if (null == dhGroup) 133 { 134 dhGroup = new DHGroup(p, null, g, 0); 135 } 136 137 if (!dhGroupVerifier.accept(dhGroup)) 138 { 139 throw new TlsFatalAlert(AlertDescription.insufficient_security); 140 } 141 return new TlsDHConfig(dhGroup); 142 } 143 144 int[] clientSupportedGroups = context.getSecurityParametersHandshake().getClientSupportedGroups(); 145 if (null == clientSupportedGroups || Arrays.contains(clientSupportedGroups, namedGroup)) 146 { 147 return new TlsDHConfig(namedGroup, false); 148 } 149 150 throw new TlsFatalAlert(AlertDescription.illegal_parameter); 151 } 152 readDHParameter(InputStream input)153 public static BigInteger readDHParameter(InputStream input) throws IOException 154 { 155 return new BigInteger(1, TlsUtils.readOpaque16(input, 1)); 156 } 157 writeDHConfig(TlsDHConfig dhConfig, OutputStream output)158 public static void writeDHConfig(TlsDHConfig dhConfig, OutputStream output) 159 throws IOException 160 { 161 DHGroup group = getDHGroup(dhConfig); 162 writeDHParameter(group.getP(), output); 163 writeDHParameter(group.getG(), output); 164 } 165 writeDHParameter(BigInteger x, OutputStream output)166 public static void writeDHParameter(BigInteger x, OutputStream output) throws IOException 167 { 168 TlsUtils.writeOpaque16(BigIntegers.asUnsignedByteArray(x), output); 169 } 170 } 171