public void generateClientKeyExchange(OutputStream os) throws IOException { /* * RFC 2246 7.4.7.2 If the client certificate already contains a suitable * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In * this case, the Client Key Exchange message will be sent, but will be empty. */ if (agreementCredentials != null) { TlsUtils.writeUint24(0, os); } else { generateEphemeralClientKeyExchange(dhAgreeServerPublicKey.getParameters(), os); } }
protected DHPublicKeyParameters validateDHPublicKey(DHPublicKeyParameters key) throws IOException { BigInteger Y = key.getY(); DHParameters params = key.getParameters(); BigInteger p = params.getP(); BigInteger g = params.getG(); if (!p.isProbablePrime(2)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } if (g.compareTo(TWO) < 0 || g.compareTo(p.subtract(TWO)) > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } if (Y.compareTo(TWO) < 0 || Y.compareTo(p.subtract(ONE)) > 0) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } // TODO See RFC 2631 for more discussion of Diffie-Hellman validation return key; }
@Override public byte[] prepareMessageAction() { // To use true DH ephemeral we need to precompute the prime number P(DH modulus) /** * int defaultPrimeProbability = 30; * * <p>DHParametersGenerator generator = new DHParametersGenerator(); //Genration of a higher bit * prime number takes too long (512 bits takes 2 seconds) generator.init(512, * defaultPrimeProbability, new SecureRandom()); DHParameters params = * generator.generateParameters(); */ DHPublicKeyParameters dhPublic; // fixed DH modulus P and DH generator G byte[] pArray = ArrayConverter.hexStringToByteArray( "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc" + "74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d" + "51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24" + "117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83" + "655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca1821" + "7c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695" + "5817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff"); byte[] gArray = {0x02}; BigInteger p = new BigInteger(1, pArray); BigInteger g = new BigInteger(1, gArray); DHParameters params = new DHParameters(p, g); KeyGenerationParameters kgp = new DHKeyGenerationParameters(new SecureRandom(), params); DHKeyPairGenerator keyGen = new DHKeyPairGenerator(); keyGen.init(kgp); AsymmetricCipherKeyPair serverKeyPair = keyGen.generateKeyPair(); dhPublic = (DHPublicKeyParameters) serverKeyPair.getPublic(); DHPrivateKeyParameters dhPrivate = (DHPrivateKeyParameters) serverKeyPair.getPrivate(); protocolMessage.setG(dhPublic.getParameters().getG()); protocolMessage.setP(dhPublic.getParameters().getP()); protocolMessage.setPublicKey(dhPublic.getY()); protocolMessage.setPrivateKey(dhPrivate.getX()); tlsContext.setServerDHPrivateKeyParameters(dhPrivate); byte[] serializedP = BigIntegers.asUnsignedByteArray(protocolMessage.getP().getValue()); protocolMessage.setSerializedP(serializedP); protocolMessage.setSerializedPLength(serializedP.length); byte[] serializedG = BigIntegers.asUnsignedByteArray(protocolMessage.getG().getValue()); protocolMessage.setSerializedG(serializedG); protocolMessage.setSerializedGLength(serializedG.length); byte[] serializedPublicKey = BigIntegers.asUnsignedByteArray(protocolMessage.getPublicKey().getValue()); protocolMessage.setSerializedPublicKey(serializedPublicKey); protocolMessage.setSerializedPublicKeyLength(serializedPublicKey.length); byte[] dhParams = ArrayConverter.concatenate( ArrayConverter.intToBytes( protocolMessage.getSerializedPLength().getValue(), HandshakeByteLength.DH_PARAM_LENGTH), protocolMessage.getSerializedP().getValue(), ArrayConverter.intToBytes( protocolMessage.getSerializedGLength().getValue(), HandshakeByteLength.DH_PARAM_LENGTH), protocolMessage.getSerializedG().getValue(), ArrayConverter.intToBytes( protocolMessage.getSerializedPublicKeyLength().getValue(), HandshakeByteLength.DH_PARAM_LENGTH), protocolMessage.getSerializedPublicKey().getValue()); InputStream is = new ByteArrayInputStream(dhParams); try { ServerDHParams publicKeyParameters = ServerDHParams.parse(is); tlsContext.setServerDHParameters(publicKeyParameters); KeyStore ks = tlsContext.getKeyStore(); // could be extended to choose the algorithms depending on the certificate SignatureAndHashAlgorithm selectedSignatureHashAlgo = new SignatureAndHashAlgorithm(SignatureAlgorithm.RSA, HashAlgorithm.SHA1); protocolMessage.setSignatureAlgorithm( selectedSignatureHashAlgo.getSignatureAlgorithm().getValue()); protocolMessage.setHashAlgorithm(selectedSignatureHashAlgo.getHashAlgorithm().getValue()); Key key = ks.getKey(tlsContext.getAlias(), tlsContext.getPassword().toCharArray()); RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; Signature instance = Signature.getInstance(selectedSignatureHashAlgo.getJavaName()); instance.initSign(rsaKey); LOGGER.debug( "SignatureAndHashAlgorithm for ServerKeyExchange message: {}", selectedSignatureHashAlgo.getJavaName()); byte[] toBeSignedBytes = ArrayConverter.concatenate( tlsContext.getClientRandom(), tlsContext.getServerRandom(), dhParams); instance.update(toBeSignedBytes); byte[] signature = instance.sign(); protocolMessage.setSignature(signature); protocolMessage.setSignatureLength(signature.length); byte[] result = ArrayConverter.concatenate( dhParams, new byte[] { protocolMessage.getHashAlgorithm().getValue(), protocolMessage.getSignatureAlgorithm().getValue() }, ArrayConverter.intToBytes( protocolMessage.getSignatureLength().getValue(), HandshakeByteLength.SIGNATURE_LENGTH), protocolMessage.getSignature().getValue()); protocolMessage.setLength(result.length); long header = (HandshakeMessageType.SERVER_KEY_EXCHANGE.getValue() << 24) + protocolMessage.getLength().getValue(); protocolMessage.setCompleteResultingMessage( ArrayConverter.concatenate(ArrayConverter.longToUint32Bytes(header), result)); } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | InvalidKeyException | SignatureException | IOException ex) { throw new ConfigurationException(ex.getLocalizedMessage(), ex); } return protocolMessage.getCompleteResultingMessage().getValue(); }