A combined hash, which implements md5(m) || sha1(m).
Наследование: IDigest
Пример #1
0
		internal RecordStream(
			TlsProtocolHandler	handler,
			Stream				inStr,
			Stream				outStr)
		{
			this.handler = handler;
			this.inStr = inStr;
			this.outStr = outStr;
			this.hash = new CombinedHash();
			this.readCipher = new TlsNullCipher();
			this.writeCipher = this.readCipher;
		}
Пример #2
0
		internal RecordStream(
			TlsProtocolHandler	handler,
			Stream				inStr,
			Stream				outStr)
		{
			this.handler = handler;
			this.inStr = inStr;
			this.outStr = outStr;
			hash1 = new CombinedHash();
			hash2 = new CombinedHash();
			this.readSuite = new TlsNullCipherSuite();
			this.writeSuite = this.readSuite;
		}
Пример #3
0
 internal RecordStream(
     TlsProtocolHandler handler,
     Stream inStr,
     Stream outStr)
 {
     this.handler          = handler;
     this.inStr            = inStr;
     this.outStr           = outStr;
     this.hash             = new CombinedHash();
     this.readCompression  = new TlsNullCompression();
     this.writeCompression = this.readCompression;
     this.readCipher       = new TlsNullCipher();
     this.writeCipher      = this.readCipher;
 }
Пример #4
0
 internal RecordStream(
     TlsProtocolHandler handler,
     Stream inStr,
     Stream outStr)
 {
     this.handler    = handler;
     this.inStr      = inStr;
     this.outStr     = outStr;
     this.hash1      = new CombinedHash();
     this.hash2      = new CombinedHash();
     this.hash3      = new CombinedHash();
     this.readSuite  = new TlsNullCipherSuite();
     this.writeSuite = this.readSuite;
 }
Пример #5
0
        public virtual TlsHandshakeHash NotifyPrfDetermined()
        {
            int prfAlgorithm = mContext.SecurityParameters.PrfAlgorithm;

            if (prfAlgorithm == 0)
            {
                CombinedHash combinedHash = new CombinedHash();
                combinedHash.Init(mContext);
                mBuf.UpdateDigest(combinedHash);
                return(combinedHash.NotifyPrfDetermined());
            }
            mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);
            CheckTrackingHash((byte)mPrfHashAlgorithm);
            return(this);
        }
Пример #6
0
        public virtual TlsHandshakeHash NotifyPrfDetermined()
        {
            int prfAlgorithm = this.mContext.SecurityParameters.PrfAlgorithm;

            if (prfAlgorithm == 0)
            {
                CombinedHash d = new CombinedHash();
                d.Init(this.mContext);
                this.mBuf.UpdateDigest(d);
                return(d.NotifyPrfDetermined());
            }
            this.mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);
            this.CheckTrackingHash((byte)this.mPrfHashAlgorithm);
            return(this);
        }
Пример #7
0
        protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
                                             ICipherParameters cp)
        {
            if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
            {
                throw new InvalidOperationException();
            }
            if (algorithm != null && algorithm.Signature != SignatureAlgorithm.rsa)
            {
                throw new InvalidOperationException();
            }

            IDigest d;

            if (raw)
            {
                d = new NullDigest();
            }
            else if (algorithm == null)
            {
                d = new CombinedHash();
            }
            else
            {
                d = TlsUtilities.CreateHash(algorithm.Hash);
            }

            ISigner s;

            if (algorithm != null)
            {
                /*
                 * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated
                 * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1].
                 */
                s = new RsaDigestSigner(d, TlsUtilities.GetOidForHashAlgorithm(algorithm.Hash));
            }
            else
            {
                /*
                 * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme
                 * that did not include a DigestInfo encoding.
                 */
                s = new GenericSigner(CreateRsaImpl(), d);
            }
            s.Init(forSigning, cp);
            return(s);
        }
        public virtual TlsHandshakeHash NotifyPrfDetermined()
        {
            int prfAlgorithm = mContext.SecurityParameters.PrfAlgorithm;
            if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
            {
                CombinedHash legacyHash = new CombinedHash();
                legacyHash.Init(mContext);
                mBuf.UpdateDigest(legacyHash);
                return legacyHash.NotifyPrfDetermined();
            }

            this.mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);

            CheckTrackingHash((byte)mPrfHashAlgorithm);

            return this;
        }
Пример #9
0
        public override byte[] GenerateServerKeyExchange()
        {
            DigestInputBuffer buf = new DigestInputBuffer();

            this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom, mNamedCurves,
                                                                                         mClientECPointFormats, buf);

            /*
             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
             */
            SignatureAndHashAlgorithm signatureAndHashAlgorithm;
            IDigest d;

            if (TlsUtilities.IsTlsV12(context))
            {
                signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
                if (signatureAndHashAlgorithm == null)
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
            }
            else
            {
                signatureAndHashAlgorithm = null;
                d = new CombinedHash();
            }

            SecurityParameters securityParameters = context.SecurityParameters;

            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
            buf.UpdateDigest(d);

            byte[] hash = DigestUtilities.DoFinal(d);

            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);

            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);

            signed_params.Encode(buf);

            return(buf.ToArray());
        }
Пример #10
0
        public override byte[] GenerateServerKeyExchange()
        {
            if (this.mDHParameters == null)
                throw new TlsFatalAlert(AlertDescription.internal_error);

            DigestInputBuffer buf = new DigestInputBuffer();

            this.mDHAgreeServerPrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom,
                this.mDHParameters, buf);

            /*
             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
             */
            SignatureAndHashAlgorithm signatureAndHashAlgorithm;
            IDigest d;

            if (TlsUtilities.IsTlsV12(context))
            {
                signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
                if (signatureAndHashAlgorithm == null)
                    throw new TlsFatalAlert(AlertDescription.internal_error);

                d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
            }
            else
            {
                signatureAndHashAlgorithm = null;
                d = new CombinedHash();
            }

            SecurityParameters securityParameters = context.SecurityParameters;
            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
            buf.UpdateDigest(d);

            byte[] hash = DigestUtilities.DoFinal(d);

            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);

            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
            signed_params.Encode(buf);

            return buf.ToArray();
        }
        protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
            ICipherParameters cp)
        {
            if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
                throw new InvalidOperationException();
            if (algorithm != null && algorithm.Signature != SignatureAlgorithm.rsa)
                throw new InvalidOperationException();

            IDigest d;
            if (raw)
            {
                d = new NullDigest();
            }
            else if (algorithm == null)
            {
                d = new CombinedHash();
            }
            else
            {
                d = TlsUtilities.CreateHash(algorithm.Hash);
            }

            ISigner s;
            if (algorithm != null)
            {
                /*
                 * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated
                 * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1].
                 */
                s = new RsaDigestSigner(d, TlsUtilities.GetOidForHashAlgorithm(algorithm.Hash));
            }
            else
            {
                /*
                 * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme
                 * that did not include a DigestInfo encoding.
                 */
                s = new GenericSigner(CreateRsaImpl(), d);
            }
            s.Init(forSigning, cp);
            return s;
        }
Пример #12
0
        protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning, ICipherParameters cp)
        {
            if (algorithm != null != TlsUtilities.IsTlsV12(this.mContext))
            {
                throw new InvalidOperationException();
            }
            if (algorithm != null && algorithm.Signature != 1)
            {
                throw new InvalidOperationException();
            }
            IDigest digest;

            if (raw)
            {
                digest = new NullDigest();
            }
            else if (algorithm == null)
            {
                digest = new CombinedHash();
            }
            else
            {
                digest = TlsUtilities.CreateHash(algorithm.Hash);
            }
            ISigner signer;

            if (algorithm != null)
            {
                signer = new RsaDigestSigner(digest, TlsUtilities.GetOidForHashAlgorithm(algorithm.Hash));
            }
            else
            {
                signer = new GenericSigner(this.CreateRsaImpl(), digest);
            }
            signer.Init(forSigning, cp);
            return(signer);
        }
Пример #13
0
		internal CombinedHash(CombinedHash t)
		{
			this.md5 = new MD5Digest(t.md5);
			this.sha1 = new Sha1Digest(t.sha1);
		}
Пример #14
0
 private static byte[] DoFinal(CombinedHash ch)
 {
     byte[] bs = new byte[ch.GetDigestSize()];
     ch.DoFinal(bs, 0);
     return(bs);
 }
Пример #15
0
 internal CombinedHash(CombinedHash t)
 {
     this.mContext = t.mContext;
     this.mMd5     = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
     this.mSha1    = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
 }
Пример #16
0
 internal CombinedHash(CombinedHash t)
 {
     this.md5  = new MD5Digest(t.md5);
     this.sha1 = new Sha1Digest(t.sha1);
 }
Пример #17
0
        public override byte[] GenerateServerKeyExchange()
        {
            /*
             * First we try to find a supported named curve from the client's list.
             */
            int namedCurve = -1;
            if (mNamedCurves == null)
            {
                // TODO Let the peer choose the default named curve
                namedCurve = NamedCurve.secp256r1;
            }
            else
            {
                for (int i = 0; i < mNamedCurves.Length; ++i)
                {
                    int entry = mNamedCurves[i];
                    if (NamedCurve.IsValid(entry) && TlsEccUtilities.IsSupportedNamedCurve(entry))
                    {
                        namedCurve = entry;
                        break;
                    }
                }
            }

            ECDomainParameters curve_params = null;
            if (namedCurve >= 0)
            {
                curve_params = TlsEccUtilities.GetParametersForNamedCurve(namedCurve);
            }
            else
            {
                /*
                 * If no named curves are suitable, check if the client supports explicit curves.
                 */
                if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_prime_curves))
                {
                    curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.secp256r1);
                }
                else if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_char2_curves))
                {
                    curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.sect283r1);
                }
            }

            if (curve_params == null)
            {
                /*
                 * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
                 * a suitable curve.
                 */
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(context.SecureRandom, curve_params);
            this.mECAgreePrivateKey = (ECPrivateKeyParameters)kp.Private;

            DigestInputBuffer buf = new DigestInputBuffer();

            if (namedCurve < 0)
            {
                TlsEccUtilities.WriteExplicitECParameters(mClientECPointFormats, curve_params, buf);
            }
            else
            {
                TlsEccUtilities.WriteNamedECParameters(namedCurve, buf);
            }

            ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
            TlsEccUtilities.WriteECPoint(mClientECPointFormats, ecPublicKey.Q, buf);

            /*
             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
             */
            SignatureAndHashAlgorithm signatureAndHashAlgorithm;
            IDigest d;

            if (TlsUtilities.IsTlsV12(context))
            {
                signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
                if (signatureAndHashAlgorithm == null)
                    throw new TlsFatalAlert(AlertDescription.internal_error);

                d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
            }
            else
            {
                signatureAndHashAlgorithm = null;
                d = new CombinedHash();
            }

            SecurityParameters securityParameters = context.SecurityParameters;
            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
            buf.UpdateDigest(d);

            byte[] hash = DigestUtilities.DoFinal(d);

            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);

            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
            signed_params.Encode(buf);

            return buf.ToArray();
        }
Пример #18
0
 private static byte[] DoFinal(CombinedHash ch)
 {
     byte[] bs = new byte[ch.GetDigestSize()];
     ch.DoFinal(bs, 0);
     return bs;
 }
Пример #19
0
        private void processHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of
                 * the message.
                 */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis  = new MemoryStream(beginning, false);
                    short        type = TlsUtilities.ReadUint8(bis);
                    int          len  = TlsUtilities.ReadUint24(bis);

                    /*
                     * Check if we have enough bytes in the buffer to read
                     * the full message.
                     */
                    if (handshakeQueue.Available >= (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.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                         * Now, parse the message.
                         */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                         * Check the type.
                         */
                        switch (type)
                        {
                        case HP_CERTIFICATE:
                            switch (connection_state)
                            {
                            case CS_SERVER_HELLO_RECEIVED:
                                /*
                                 * Parse the certificates.
                                 */
                                Certificate cert = Certificate.Parse(inStr);
                                AssertEmpty(inStr);

                                /*
                                 * 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].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey());
                                }
                                catch (Exception)
                                {
                                    /*
                                     * Sorry, we have to fail ;-(
                                     */
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                }

                                /*
                                 * Parse the servers public RSA key.
                                 */
                                this.serverRsaKey = new RsaKeyParameters(
                                    false,
                                    rsaKey.Modulus,
                                    rsaKey.PublicExponent);

                                connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            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];
                                TlsUtilities.ReadFully(receivedChecksum, inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Calculate our owne checksum.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash2.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), 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;
                            }
                            break;

                        case HP_SERVER_HELLO:
                            switch (connection_state)
                            {
                            case CS_CLIENT_HELLO_SEND:
                                /*
                                 * Read the server hello message
                                 */
                                TlsUtilities.CheckVersion(inStr, this);

                                /*
                                 * Read the server random
                                 */
                                this.serverRandom = new byte[32];
                                TlsUtilities.ReadFully(this.serverRandom, inStr);

                                /*
                                 * Currenty, we don't support session ids
                                 */
                                short  sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                byte[] sessionId       = new byte[sessionIdLength];
                                TlsUtilities.ReadFully(sessionId, inStr);

                                /*
                                 * 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(
                                    TlsUtilities.ReadUint16(inStr), this);

                                /*
                                 * We support only the null compression which
                                 * means no compression.
                                 */
                                short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                if (compressionMethod != 0)
                                {
                                    this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                }
                                AssertEmpty(inStr);

                                connection_state = CS_SERVER_HELLO_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO_DONE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:

                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                AssertEmpty(inStr);
                                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.KeyExchangeAlgorithm;

                                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;
                                    random.NextBytes(pms, 2, 46);

                                    /*
                                     * 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)
                                    {
                                        /*
                                         * This should never happen, only during decryption.
                                         */
                                        this.FailWithError(AL_fatal, AP_internal_error);
                                    }

                                    /*
                                     * Send the encrypted pms.
                                     */
                                    MemoryStream bos = new MemoryStream();
                                    TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos);
                                    TlsUtilities.WriteUint24(encrypted.Length + 2, bos);
                                    TlsUtilities.WriteUint16(encrypted.Length, bos);
                                    bos.Write(encrypted, 0, encrypted.Length);
                                    byte[] message = bos.ToArray();

                                    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();
                                    MemoryStream DHbos  = new MemoryStream();
                                    TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
                                    TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos);
                                    TlsUtilities.WriteUint16(YcByte.Length, DHbos);
                                    DHbos.Write(YcByte, 0, YcByte.Length);
                                    byte[] DHmessage = DHbos.ToArray();

                                    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);
                                    break;
                                }

                                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[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, 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);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                MemoryStream bos2 = new MemoryStream();
                                TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                TlsUtilities.WriteUint24(12, bos2);
                                bos2.Write(checksum, 0, checksum.Length);
                                byte[] message2 = bos2.ToArray();

                                rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                this.connection_state = CS_CLIENT_FINISHED_SEND;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_handshake_failure);
                                break;
                            }
                            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.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA)
                                {
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                }

                                /*
                                 * Parse the Structure
                                 */
                                int    pLength = TlsUtilities.ReadUint16(inStr);
                                byte[] pByte   = new byte[pLength];
                                TlsUtilities.ReadFully(pByte, inStr);

                                int    gLength = TlsUtilities.ReadUint16(inStr);
                                byte[] gByte   = new byte[gLength];
                                TlsUtilities.ReadFully(gByte, inStr);

                                int    YsLength = TlsUtilities.ReadUint16(inStr);
                                byte[] YsByte   = new byte[YsLength];
                                TlsUtilities.ReadFully(YsByte, inStr);

                                int    sigLength = TlsUtilities.ReadUint16(inStr);
                                byte[] sigByte   = new byte[sigLength];
                                TlsUtilities.ReadFully(sigByte, inStr);

                                this.AssertEmpty(inStr);

                                /*
                                 * Verify the Signature.
                                 *
                                 * First, calculate the hash.
                                 */
                                CombinedHash sigDigest  = new CombinedHash();
                                MemoryStream signedData = new MemoryStream();
                                TlsUtilities.WriteUint16(pLength, signedData);
                                signedData.Write(pByte, 0, pByte.Length);
                                TlsUtilities.WriteUint16(gLength, signedData);
                                signedData.Write(gByte, 0, gByte.Length);
                                TlsUtilities.WriteUint16(YsLength, signedData);
                                signedData.Write(YsByte, 0, YsByte.Length);
                                byte[] signed = signedData.ToArray();

                                sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
                                sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);
                                sigDigest.BlockUpdate(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)
                                {
                                    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];
                                    Array.Copy(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;
                            }
                            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);
        }
Пример #20
0
        private void processHandshake()
        {
            bool read;
            do
            {
                read = false;

                /*
                * We need the first 4 bytes, they contain type and length of
                * the message.
                */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis = new MemoryStream(beginning, false);
                    short type = TlsUtilities.ReadUint8(bis);
                    int len = TlsUtilities.ReadUint24(bis);

                    /*
                    * Check if we have enough bytes in the buffer to read
                    * the full message.
                    */
                    if (handshakeQueue.Available >= (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.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                        * Now, parse the message.
                        */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                        * Check the type.
                        */
                        switch (type)
                        {
                            case HP_CERTIFICATE:
                                switch (connection_state)
                                {
                                    case CS_SERVER_HELLO_RECEIVED:
                                        /*
                                        * Parse the certificates.
                                        */
                                        Certificate cert = Certificate.Parse(inStr);
                                        AssertEmpty(inStr);

                                        /*
                                        * 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].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey());
                                        }
                                        catch (Exception)
                                        {
                                            /*
                                            * Sorry, we have to fail ;-(
                                            */
                                            this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                        }

                                        /*
                                        * Parse the servers public RSA key.
                                        */
                                        this.serverRsaKey = new RsaKeyParameters(
                                            false,
                                            rsaKey.Modulus,
                                            rsaKey.PublicExponent);

                                        connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                        break;
                                }
                                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];
                                        TlsUtilities.ReadFully(receivedChecksum, inStr);
                                        AssertEmpty(inStr);

                                        /*
                                        * Calculate our owne checksum.
                                        */
                                        byte[] checksum = new byte[12];
                                        byte[] md5andsha1 = new byte[16 + 20];
                                        rs.hash2.DoFinal(md5andsha1, 0);
                                        TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), 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;
                                }
                                break;
                            case HP_SERVER_HELLO:
                                switch (connection_state)
                                {
                                    case CS_CLIENT_HELLO_SEND:
                                        /*
                                        * Read the server hello message
                                        */
                                        TlsUtilities.CheckVersion(inStr, this);

                                        /*
                                        * Read the server random
                                        */
                                        this.serverRandom = new byte[32];
                                        TlsUtilities.ReadFully(this.serverRandom, inStr);

                                        /*
                                        * Currenty, we don't support session ids
                                        */
                                        short sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                        byte[] sessionId = new byte[sessionIdLength];
                                        TlsUtilities.ReadFully(sessionId, inStr);

                                        /*
                                        * 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(
                                            TlsUtilities.ReadUint16(inStr), this);

                                        /*
                                        * We support only the null compression which
                                        * means no compression.
                                        */
                                        short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                        if (compressionMethod != 0)
                                        {
                                            this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                        }
                                        AssertEmpty(inStr);

                                        connection_state = CS_SERVER_HELLO_RECEIVED;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                        break;
                                }
                                break;
                            case HP_SERVER_HELLO_DONE:
                                switch (connection_state)
                                {
                                    case CS_SERVER_CERTIFICATE_RECEIVED:
                                    case CS_SERVER_KEY_EXCHANGE_RECEIVED:

                                        // NB: Original code used case label fall-through
                                        if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                        {
                                            /*
                                            * There was no server key exchange message, check
                                            * that we are doing RSA key exchange.
                                            */
                                            if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                            {
                                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                            }
                                        }

                                        AssertEmpty(inStr);
                                        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.KeyExchangeAlgorithm;

                                        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;
                                                random.NextBytes(pms, 2, 46);

                                                /*
                                                * 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)
                                                {
                                                    /*
                                                    * This should never happen, only during decryption.
                                                    */
                                                    this.FailWithError(AL_fatal, AP_internal_error);
                                                }

                                                /*
                                                * Send the encrypted pms.
                                                */
                                                MemoryStream bos = new MemoryStream();
                                                TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos);
                                                TlsUtilities.WriteUint24(encrypted.Length + 2, bos);
                                                TlsUtilities.WriteUint16(encrypted.Length, bos);
                                                bos.Write(encrypted, 0, encrypted.Length);
                                                byte[] message = bos.ToArray();

                                                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();
                                                MemoryStream DHbos = new MemoryStream();
                                                TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos);
                                                TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos);
                                                TlsUtilities.WriteUint16(YcByte.Length, DHbos);
                                                DHbos.Write(YcByte, 0, YcByte.Length);
                                                byte[] DHmessage = DHbos.ToArray();

                                                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);
                                                break;

                                        }

                                        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[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                        Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                        Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                        TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, 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);
                                        TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                        MemoryStream bos2 = new MemoryStream();
                                        TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                        TlsUtilities.WriteUint24(12, bos2);
                                        bos2.Write(checksum, 0, checksum.Length);
                                        byte[] message2 = bos2.ToArray();

                                        rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                        this.connection_state = CS_CLIENT_FINISHED_SEND;
                                        read = true;
                                        break;
                                    default:
                                        this.FailWithError(AL_fatal, AP_handshake_failure);
                                        break;
                                }
                                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.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA)
                                        {
                                            this.FailWithError(AL_fatal, AP_unexpected_message);
                                        }

                                        /*
                                        * Parse the Structure
                                        */
                                        int pLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] pByte = new byte[pLength];
                                        TlsUtilities.ReadFully(pByte, inStr);

                                        int gLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] gByte = new byte[gLength];
                                        TlsUtilities.ReadFully(gByte, inStr);

                                        int YsLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] YsByte = new byte[YsLength];
                                        TlsUtilities.ReadFully(YsByte, inStr);

                                        int sigLength = TlsUtilities.ReadUint16(inStr);
                                        byte[] sigByte = new byte[sigLength];
                                        TlsUtilities.ReadFully(sigByte, inStr);

                                        this.AssertEmpty(inStr);

                                        /*
                                        * Verify the Signature.
                                        *
                                        * First, calculate the hash.
                                        */
                                        CombinedHash sigDigest = new CombinedHash();
                                        MemoryStream signedData = new MemoryStream();
                                        TlsUtilities.WriteUint16(pLength, signedData);
                                        signedData.Write(pByte, 0, pByte.Length);
                                        TlsUtilities.WriteUint16(gLength, signedData);
                                        signedData.Write(gByte, 0, gByte.Length);
                                        TlsUtilities.WriteUint16(YsLength, signedData);
                                        signedData.Write(YsByte, 0, YsByte.Length);
                                        byte[] signed = signedData.ToArray();

                                        sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
                                        sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);
                                        sigDigest.BlockUpdate(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)
                                        {
                                            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];
                                            Array.Copy(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;
                                }
                                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);
        }
Пример #21
0
 internal CombinedHash(CombinedHash t)
 {
     this.mContext = t.mContext;
     this.mMd5     = TlsUtilities.CloneHash(1, t.mMd5);
     this.mSha1    = TlsUtilities.CloneHash(2, t.mSha1);
 }
Пример #22
0
 internal CombinedHash(CombinedHash t)
 {
     this.mContext = t.mContext;
     this.mMd5 = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
     this.mSha1 = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
 }
Пример #23
0
        public override byte[] GenerateServerKeyExchange()
        {
            /*
             * First we try to find a supported named curve from the client's list.
             */
            int namedCurve = -1;

            if (mNamedCurves == null)
            {
                // TODO Let the peer choose the default named curve
                namedCurve = NamedCurve.secp256r1;
            }
            else
            {
                for (int i = 0; i < mNamedCurves.Length; ++i)
                {
                    int entry = mNamedCurves[i];
                    if (NamedCurve.IsValid(entry) && TlsEccUtilities.IsSupportedNamedCurve(entry))
                    {
                        namedCurve = entry;
                        break;
                    }
                }
            }

            ECDomainParameters curve_params = null;

            if (namedCurve >= 0)
            {
                curve_params = TlsEccUtilities.GetParametersForNamedCurve(namedCurve);
            }
            else
            {
                /*
                 * If no named curves are suitable, check if the client supports explicit curves.
                 */
                if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_prime_curves))
                {
                    curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.secp256r1);
                }
                else if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_char2_curves))
                {
                    curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.sect283r1);
                }
            }

            if (curve_params == null)
            {
                /*
                 * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
                 * a suitable curve.
                 */
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(context.SecureRandom, curve_params);

            this.mECAgreePrivateKey = (ECPrivateKeyParameters)kp.Private;

            DigestInputBuffer buf = new DigestInputBuffer();

            if (namedCurve < 0)
            {
                TlsEccUtilities.WriteExplicitECParameters(mClientECPointFormats, curve_params, buf);
            }
            else
            {
                TlsEccUtilities.WriteNamedECParameters(namedCurve, buf);
            }

            ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;

            TlsEccUtilities.WriteECPoint(mClientECPointFormats, ecPublicKey.Q, buf);

            /*
             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
             */
            SignatureAndHashAlgorithm signatureAndHashAlgorithm;
            IDigest d;

            if (TlsUtilities.IsTlsV12(context))
            {
                signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
                if (signatureAndHashAlgorithm == null)
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
            }
            else
            {
                signatureAndHashAlgorithm = null;
                d = new CombinedHash();
            }

            SecurityParameters securityParameters = context.SecurityParameters;

            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
            buf.UpdateDigest(d);

            byte[] hash = DigestUtilities.DoFinal(d);

            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);

            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);

            signed_params.Encode(buf);

            return(buf.ToArray());
        }