pms[i] = (byte)random.nextInt(256);
pms[i] = (byte)random.nextInt();
    private void processHandshake() throws IOException    {        boolean read;        do        {            read = false;            /*            * We need the first 4 bytes, they contain type and length of            * the message.            */            if (handshakeQueue.size() >= 4)            {                byte[] beginning = new byte[4];                handshakeQueue.read(beginning, 0, 4, 0);                ByteArrayInputStream bis = new ByteArrayInputStream(beginning);                short type = TlsUtils.readUint8(bis);                int len = TlsUtils.readUint24(bis);                /*                * Check if we have enough bytes in the buffer to read                * the full message.                */                if (handshakeQueue.size() >= (len + 4))                {                    /*                     * Read the message.                     */                    byte[] buf = new byte[len];                    handshakeQueue.read(buf, 0, len, 4);                    handshakeQueue.removeData(len + 4);                    /*                    * If it is not a finished message, update our hashes                    * we prepare for the finish message.                    */                    if (type != HP_FINISHED)                    {                        rs.hash1.update(beginning, 0, 4);                        rs.hash2.update(beginning, 0, 4);                        rs.hash1.update(buf, 0, len);                        rs.hash2.update(buf, 0, len);                    }                    /*                    * Now, parse the message.                    */                    ByteArrayInputStream is = new ByteArrayInputStream(buf);                    /*                    * Check the type.                    */                    switch (type)                    {                        case HP_CERTIFICATE:                            switch (connection_state)                            {                                case CS_SERVER_HELLO_RECEIVED:                                    /*                                    * Parse the certificates.                                    */                                    Certificate cert = Certificate.parse(is);                                    assertEmpty(is);                                    /*                                    * Verify them.                                    */                                    if (!this.verifyer.isValid(cert.getCerts()))                                    {                                        this.failWithError(AL_fatal, AP_user_canceled);                                    }                                    /*                                    * We only support RSA certificates. Lets hope                                    * this is one.                                    */                                    RSAPublicKeyStructure rsaKey = null;                                    try                                    {                                        rsaKey = RSAPublicKeyStructure.getInstance(cert.certs[0].getTBSCertificate().getSubjectPublicKeyInfo().getPublicKey());                                    }                                    catch (Exception e)                                    {                                        /*                                        * Sorry, we have to fail ;-(                                        */                                        this.failWithError(AL_fatal, AP_unsupported_certificate);                                    }                                    /*                                    * Parse the servers public RSA key.                                    */                                    this.serverRsaKey = new RSAKeyParameters(                                        false,                                        rsaKey.getModulus(),                                        rsaKey.getPublicExponent());                                    connection_state = CS_SERVER_CERTIFICATE_RECEIVED;                                    read = true;                                    break;                                default:                                    this.failWithError(AL_fatal, AP_unexpected_message);                            }                            break;                        case HP_FINISHED:                            switch (connection_state)                            {                                case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:                                    /*                                    * Read the checksum from the finished message,                                    * it has always 12 bytes.                                    */                                    byte[] receivedChecksum = new byte[12];                                    TlsUtils.readFully(receivedChecksum, is);                                    assertEmpty(is);                                    /*                                    * Calculate our owne checksum.                                    */                                    byte[] checksum = new byte[12];                                    byte[] md5andsha1 = new byte[16 + 20];                                    rs.hash2.doFinal(md5andsha1, 0);                                    TlsUtils.PRF(this.ms, "server finished".getBytes(), md5andsha1, checksum);                                    /*                                    * Compare both checksums.                                    */                                    for (int i = 0; i < receivedChecksum.length; i++)                                    {                                        if (receivedChecksum[i] != checksum[i])                                        {                                            /*                                            * Wrong checksum in the finished message.                                            */                                            this.failWithError(AL_fatal, AP_handshake_failure);                                        }                                    }                                    connection_state = CS_DONE;                                    /*                                    * We are now ready to receive application data.                                    */                                    this.appDataReady = true;                                    read = true;                                    break;                                default:                                    this.failWithError(AL_fatal, AP_unexpected_message);                            }                            break;                        case HP_SERVER_HELLO:                            switch (connection_state)                            {                                case CS_CLIENT_HELLO_SEND:                                    /*                                    * Read the server hello message                                    */                                    TlsUtils.checkVersion(is, this);                                    /*                                    * Read the server random                                    */                                    this.serverRandom = new byte[32];                                    TlsUtils.readFully(this.serverRandom, is);                                    /*                                    * Currenty, we don't support session ids                                    */                                    short sessionIdLength = TlsUtils.readUint8(is);                                    byte[] sessionId = new byte[sessionIdLength];                                    TlsUtils.readFully(sessionId, is);                                    /*                                    * Find out which ciphersuite the server has                                    * choosen. If we don't support this ciphersuite,                                    * the TlsCipherSuiteManager will throw an                                    * exception.                                    */                                    this.choosenCipherSuite = TlsCipherSuiteManager.getCipherSuite(TlsUtils.readUint16(is), this);                                    /*                                    * We support only the null compression which                                    * means no compression.                                    */                                    short compressionMethod = TlsUtils.readUint8(is);                                    if (compressionMethod != 0)                                    {                                        this.failWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);                                    }                                    assertEmpty(is);                                    connection_state = CS_SERVER_HELLO_RECEIVED;                                    read = true;                                    break;                                default:                                    this.failWithError(AL_fatal, AP_unexpected_message);                            }                            break;                        case HP_SERVER_HELLO_DONE:                            switch (connection_state)                            {                                case CS_SERVER_CERTIFICATE_RECEIVED:                                    /*                                    * There was no server key exchange message, check                                    * that we are doing RSA key exchange.                                    */                                    if (this.choosenCipherSuite.getKeyExchangeAlgorithm() != TlsCipherSuite.KE_RSA)                                    {                                        this.failWithError(AL_fatal, AP_unexpected_message);                                    }                                    /*                                    * NB: Fall through to next case label to continue RSA key exchange                                    */                                case CS_SERVER_KEY_EXCHANGE_RECEIVED:                                    assertEmpty(is);                                    connection_state = CS_SERVER_HELLO_DONE_RECEIVED;                                    /*                                    * Send the client key exchange message, depending                                    * on the key exchange we are using in our                                    * ciphersuite.                                    */                                    short ke = this.choosenCipherSuite.getKeyExchangeAlgorithm();                                    switch (ke)                                    {                                        case TlsCipherSuite.KE_RSA:                                            /*                                            * We are doing RSA key exchange. We will                                            * choose a pre master secret and send it                                            * rsa encrypted to the server.                                            *                                            * Prepare pre master secret.                                            */                                            pms = new byte[48];                                            pms[0] = 3;                                            pms[1] = 1;                                            for (int i = 2; i < 48; i++)                                            {                                                pms[i] = (byte)random.nextInt(256);                                            }                                            /*                                            * Encode the pms and send it to the server.                                            *                                            * Prepare an PKCS1Encoding with good random                                            * padding.                                            */                                            RSABlindedEngine rsa = new RSABlindedEngine();                                            PKCS1Encoding encoding = new PKCS1Encoding(rsa);                                            encoding.init(true, new ParametersWithRandom(this.serverRsaKey, this.random));                                            byte[] encrypted = null;                                            try                                            {                                                encrypted = encoding.processBlock(pms, 0, pms.length);                                            }                                            catch (InvalidCipherTextException e)                                            {                                                /*                                                * This should never happen, only during decryption.                                                */                                                this.failWithError(AL_fatal, AP_internal_error);                                            }                                            /*                                            * Send the encrypted pms.                                            */                                            ByteArrayOutputStream bos = new ByteArrayOutputStream();                                            TlsUtils.writeUint8(HP_CLIENT_KEY_EXCHANGE, bos);                                            TlsUtils.writeUint24(encrypted.length + 2, bos);                                            TlsUtils.writeUint16(encrypted.length, bos);                                            bos.write(encrypted);                                            byte[] message = bos.toByteArray();                                            rs.writeMessage((short)RL_HANDSHAKE, message, 0, message.length);                                            break;                                        case TlsCipherSuite.KE_DHE_RSA:                                            /*                                            * Send the Client Key Exchange message for                                            * DHE key exchange.                                            */                                            byte[] YcByte = this.Yc.toByteArray();                                            ByteArrayOutputStream DHbos = new ByteArrayOutputStream();                                            TlsUtils.writeUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);                                            TlsUtils.writeUint24(YcByte.length + 2, DHbos);                                            TlsUtils.writeUint16(YcByte.length, DHbos);                                            DHbos.write(YcByte);                                            byte[] DHmessage = DHbos.toByteArray();                                            rs.writeMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.length);                                            break;                                        default:                                            /*                                            * Proble during handshake, we don't know                                            * how to thandle this key exchange method.                                            */                                            this.failWithError(AL_fatal, AP_unexpected_message);                                    }                                    connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;                                    /*                                    * Now, we send change cipher state                                    */                                    byte[] cmessage = new byte[1];                                    cmessage[0] = 1;                                    rs.writeMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.length);                                    connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;                                    /*                                    * Calculate the ms                                    */                                    this.ms = new byte[48];                                    byte[] random = new byte[clientRandom.length + serverRandom.length];                                    System.arraycopy(clientRandom, 0, random, 0, clientRandom.length);                                    System.arraycopy(serverRandom, 0, random, clientRandom.length, serverRandom.length);                                    TlsUtils.PRF(pms, "master secret".getBytes(), random, this.ms);                                    /*                                    * Initialize our cipher suite                                    */                                    rs.writeSuite = this.choosenCipherSuite;                                    rs.writeSuite.init(this.ms, clientRandom, serverRandom);                                    /*                                    * Send our finished message.                                    */                                    byte[] checksum = new byte[12];                                    byte[] md5andsha1 = new byte[16 + 20];                                    rs.hash1.doFinal(md5andsha1, 0);                                    TlsUtils.PRF(this.ms, "client finished".getBytes(), md5andsha1, checksum);                                    ByteArrayOutputStream bos = new ByteArrayOutputStream();                                    TlsUtils.writeUint8(HP_FINISHED, bos);                                    TlsUtils.writeUint24(12, bos);                                    bos.write(checksum);                                    byte[] message = bos.toByteArray();                                    rs.writeMessage((short)RL_HANDSHAKE, message, 0, message.length);                                    this.connection_state = CS_CLIENT_FINISHED_SEND;                                    read = true;                                    break;                                default:                                    this.failWithError(AL_fatal, AP_handshake_failure);                            }                            break;                        case HP_SERVER_KEY_EXCHANGE:                            switch (connection_state)                            {                                case CS_SERVER_CERTIFICATE_RECEIVED:                                    /*                                    * Check that we are doing DHE key exchange                                    */                                    if (this.choosenCipherSuite.getKeyExchangeAlgorithm() != TlsCipherSuite.KE_DHE_RSA)                                    {                                        this.failWithError(AL_fatal, AP_unexpected_message);                                    }                                    /*                                    * Parse the Structure                                    */                                    int pLength = TlsUtils.readUint16(is);                                    byte[] pByte = new byte[pLength];                                    TlsUtils.readFully(pByte, is);                                    int gLength = TlsUtils.readUint16(is);                                    byte[] gByte = new byte[gLength];                                    TlsUtils.readFully(gByte, is);                                    int YsLength = TlsUtils.readUint16(is);                                    byte[] YsByte = new byte[YsLength];                                    TlsUtils.readFully(YsByte, is);                                    int sigLength = TlsUtils.readUint16(is);                                    byte[] sigByte = new byte[sigLength];                                    TlsUtils.readFully(sigByte, is);                                    this.assertEmpty(is);                                    /*                                    * Verify the Signature.                                    *                                    * First, calculate the hash.                                    */                                    CombinedHash sigDigest = new CombinedHash();                                    ByteArrayOutputStream signedData = new ByteArrayOutputStream();                                    TlsUtils.writeUint16(pLength, signedData);                                    signedData.write(pByte);                                    TlsUtils.writeUint16(gLength, signedData);                                    signedData.write(gByte);                                    TlsUtils.writeUint16(YsLength, signedData);                                    signedData.write(YsByte);                                    byte[] signed = signedData.toByteArray();                                    sigDigest.update(this.clientRandom, 0, this.clientRandom.length);                                    sigDigest.update(this.serverRandom, 0, this.serverRandom.length);                                    sigDigest.update(signed, 0, signed.length);                                    byte[] hash = new byte[sigDigest.getDigestSize()];                                    sigDigest.doFinal(hash, 0);                                    /*                                    * Now, do the RSA operation                                    */                                    RSABlindedEngine rsa = new RSABlindedEngine();                                    PKCS1Encoding encoding = new PKCS1Encoding(rsa);                                    encoding.init(false, this.serverRsaKey);                                    /*                                    * The data which was signed                                    */                                    byte[] sigHash = null;                                    try                                    {                                        sigHash = encoding.processBlock(sigByte, 0, sigByte.length);                                    }                                    catch (InvalidCipherTextException e)                                    {                                        this.failWithError(AL_fatal, AP_bad_certificate);                                    }                                    /*                                    * Check if the data which was signed is equal to                                    * the hash we calculated.                                    */                                    if (sigHash.length != hash.length)                                    {                                        this.failWithError(AL_fatal, AP_bad_certificate);                                    }                                    for (int i = 0; i < sigHash.length; i++)                                    {                                        if (sigHash[i] != hash[i])                                        {                                            this.failWithError(AL_fatal, AP_bad_certificate);                                        }                                    }                                    /*                                    * OK, Signature was correct.                                    *                                    * Do the DH calculation.                                    */                                    BigInteger p = new BigInteger(1, pByte);                                    BigInteger g = new BigInteger(1, gByte);                                    BigInteger Ys = new BigInteger(1, YsByte);                                    BigInteger x = new BigInteger(p.bitLength() - 1, this.random);                                    Yc = g.modPow(x, p);                                    this.pms = (Ys.modPow(x, p)).toByteArray();                                    /*                                    * Remove leading zero byte, if present.                                    */                                    if (this.pms[0] == 0)                                    {                                        byte[] tmp = new byte[this.pms.length - 1];                                        System.arraycopy(this.pms, 1, tmp, 0, tmp.length);                                        this.pms = tmp;                                    }                                    this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;                                    read = true;                                    break;                                default:                                    this.failWithError(AL_fatal, AP_unexpected_message);                            }                            break;                        case HP_HELLO_REQUEST:                        case HP_CLIENT_KEY_EXCHANGE:                        case HP_CERTIFICATE_REQUEST:                        case HP_CERTIFICATE_VERIFY:                        case HP_CLIENT_HELLO:                        default:                            // We do not support this!                            this.failWithError(AL_fatal, AP_unexpected_message);                            break;                    }                }            }        }        while (read);    }