Esempio n. 1
0
        void HandleHandshakeMessage(TLSHandShakeMessage msg)
        {
            /// Append all our handshake data because we'll need it later for some stupid reason

            if (msg.HandShakeMessageType == HandShakeMessageType.ServerHello)
            {
                ClientTLSState = TLS.ClientTLSState.ReceivedServerHello;
            }
            else if (msg.HandShakeMessageType == HandShakeMessageType.ServerHelloDone)
            {
                if (m_bSendClientCertificate == true) /// got a certificate request from the server, but we don't have any, so send an empty one
                {
                    TLSHandShakeMessage msgclientcert = new TLSHandShakeMessage();
                    msgclientcert.HandShakeMessageType = HandShakeMessageType.Certificate;
                    TLSRecord recordclientcert = new TLSRecord();
                    recordclientcert.MajorVersion = 3;
                    recordclientcert.MinorVersion = 1;
                    recordclientcert.ContentType  = TLSContentType.Handshake;
                    recordclientcert.Messages.Add(msgclientcert);

                    SendTLSRecord(recordclientcert, true);
                }

                /// Server has sent the algorithm they want us to use, certificates, parameters,
                /// and any request for certificates from us.  Now let's respond
                /// First generate, encrypt, and send the PreMasterSecret

                byte [] bKey             = state.SecurityParameters.PeerCertificate.GetPublicKey();
                byte [] bPreMasterSecret = new byte[48];
                RNGCryptoServiceProvider.GetBytes(bPreMasterSecret); /// Get some random bytes
                bPreMasterSecret[0] = 0x03;                          /// first two bytes get set to the version
                bPreMasterSecret[1] = 0x01;

                /// Openssl is showing our modulus as having an extra 00 on the front when using this command
                /// (ignore this, the modulus lower in the output doesn't show the 0)
                /// rsa -in test_key.pem -text

                if (SocketClient.ShowDebug == true)
                {
                    System.Diagnostics.Debug.WriteLine("Client Random: +++++++++++\r\n{0}\r\n++++++++++++", ByteHelper.HexStringFromByte(state.SecurityParameters.ClientRandom, true, 16));
                    System.Diagnostics.Debug.WriteLine("Server Random: +++++++++++\r\n{0}\r\n++++++++++++", ByteHelper.HexStringFromByte(state.SecurityParameters.ServerRandom, true, 16));
                    System.Diagnostics.Debug.WriteLine("PreMasterSecret: +++++++++++\r\n{0}\r\n++++++++++++", ByteHelper.HexStringFromByte(bPreMasterSecret, true, 16));
                }

                RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
                // Need to use this guys' class to parse the DER encoded ASN.1 described certificate to
                // extract the modulus and e from the certificate - these two are the public key
                RSAParameters rsaparams = Kishore.X509.Parser.X509PublicKeyParser.GetRSAPublicKeyParameters(bKey);
                provider.ImportParameters(rsaparams);

                //System.Diagnostics.Debug.WriteLine("Public key modulus: +++++++++++\r\n{0}\r\n++++++++++++", ByteHelper.HexStringFromByte(rsaparams.Modulus, true, 16));
                //System.Diagnostics.Debug.WriteLine("Public key exponent: +++++++++++\r\n{0}\r\n++++++++++++", ByteHelper.HexStringFromByte(rsaparams.Exponent, true, 16));
                //System.Diagnostics.Debug.WriteLine("Key Exchange Algorithm: {0}, KeySize: {1}", provider.KeyExchangeAlgorithm, provider.KeySize);
                byte[] EncryptedPreMasterSecret = provider.Encrypt(bPreMasterSecret, false);
                provider.Dispose();

                /// Send a Client Key Exchange method with our PreMasterSecret
                ///
                TLSHandShakeMessage msgsend = new TLSHandShakeMessage();
                msgsend.HandShakeMessageType = HandShakeMessageType.ClientKeyExchange;
                msgsend.HandShakeClientKeyExchange.EncryptedPreMasterSecret = EncryptedPreMasterSecret;
                msgsend.HandShakeClientKeyExchange.KeyExchangeAlgorithm     = KeyExchangeAlgorithm.rsa;
                msgsend.HandShakeClientKeyExchange.PublicValueEncoding      = PublicValueEncoding.explicit_en;
                TLSRecord record = new TLSRecord();
                record.MajorVersion = 3;
                record.MinorVersion = 1;
                record.ContentType  = TLSContentType.Handshake;
                record.Messages.Add(msgsend);

                SendTLSRecord(record, true);



                /// Now generate all our keys, etc
                /// Section 8.1
                /// master_secret = PRF(pre_master_secret, "master secret",ClientHello.random + ServerHello.random) [0..47];

                // Combine ClientHello.Random and ServerHello.Random
                ByteBuffer buf = new ByteBuffer();
                buf.AppendData(state.SecurityParameters.ClientRandom);
                buf.AppendData(state.SecurityParameters.ServerRandom);
                byte [] bCSRandom = buf.GetAllSamples();

                // Do it in reverse order for different algorithms
                buf.AppendData(state.SecurityParameters.ServerRandom);
                buf.AppendData(state.SecurityParameters.ClientRandom);
                byte [] bSCRandom = buf.GetAllSamples();

                state.SecurityParameters.MasterSecret = state.PRF(bPreMasterSecret, "master secret", bCSRandom, 48);

                if (SocketClient.ShowDebug == true)
                {
                    System.Diagnostics.Debug.WriteLine("MasterSecret: +++++++++++\r\n{0}\r\n++++++++++++", ByteHelper.HexStringFromByte(state.SecurityParameters.MasterSecret, true, 16));
                }

                /// Verified that we are computing all our keys correctly by using the same input into the Mentalis library
                /// If we coded ours independently and get the same answers, it has to be correct, or we made the same mistakes :)
                state.ComputeKeys(state.SecurityParameters.MasterSecret, bSCRandom);



                /// Now send out a change cipher-spec, followed by a client finished message that is encrypted
                ///
                TLSChangeCipherSpecMessage msgChangeCipherSpec = new TLSChangeCipherSpecMessage();
                msgChangeCipherSpec.CCSProtocolType = CCSProtocolType.Default;
                TLSRecord recordccs = new TLSRecord();
                recordccs.MajorVersion = 3;
                recordccs.MinorVersion = 1;
                recordccs.ContentType  = TLSContentType.ChangeCipherSpec;
                recordccs.Messages.Add(msgChangeCipherSpec);
                SendTLSRecord(recordccs, false);

                state.SendEncryptionActive = true;
                state.WriteSequenceNumber  = 0; /// reset on changecipherspec

                /// Now send a finished method, encrypted with our generated things
                /// RFC2246 section 7.4.9

                if (SocketClient.ShowDebug == true)
                {
                    System.Diagnostics.Debug.WriteLine("FINAL:  AllHandShakeMessages Length is now {0}", AllHandShakeMessages.Size);
                }

                SHA1Managed sha1 = new SHA1Managed();
                byte[]      bAllHandshakeData        = AllHandShakeMessages.PeekAllSamples();
                byte[]      bmd5OfHandshakeMessages  = MD5Core.GetHash(bAllHandshakeData);
                byte[]      bsha1OfHandshakeMessages = sha1.ComputeHash(bAllHandshakeData);
                ByteBuffer  bSum = new ByteBuffer();
                bSum.AppendData(bmd5OfHandshakeMessages);
                bSum.AppendData(bsha1OfHandshakeMessages);

                byte [] bCombinedHashes = bSum.GetAllSamples();

                /// No use in writing out this debug, only a few of the characters get seen, the rest are dropped
                ///System.Diagnostics.Debug.WriteLine("**** Start all handshake data ****\r\n{0}\r\n**** End all handshake data ****", ByteHelper.HexStringFromByte(bAllHandshakeData, true, 32));
                /// verify_data
                ///     PRF(master_secret, finished_label, MD5(handshake_messages) + SHA-1(handshake_messages)) [0..11];

                TLSHandShakeMessage msgFinished = new TLSHandShakeMessage();
                msgFinished.HandShakeMessageType          = HandShakeMessageType.Finished;
                msgFinished.HandShakeFinished.verify_data = state.PRF(state.SecurityParameters.MasterSecret, "client finished", bCombinedHashes, 12);

                TLSRecord recordFinished = new TLSRecord();
                recordFinished.MajorVersion = 3;
                recordFinished.MinorVersion = 1;
                recordFinished.ContentType  = TLSContentType.Handshake;
                recordFinished.Messages.Add(msgFinished);

                state.WriteSequenceNumber = 0;
                /// This record must now be encrypted before it can be sent
                SendTLSRecord(recordFinished, true);


                ClientTLSState = ClientTLSState.SentClientFinished;
            }
            else if (msg.HandShakeMessageType == HandShakeMessageType.Finished)
            {
                /// Got the server finished method, let's verify the data
                ///
                SHA1Managed sha1 = new SHA1Managed();
                byte[]      bAllHandshakeData        = AllHandShakeMessages.GetAllSamples(); // no need to peek here, just get it all and clear it
                byte[]      bmd5OfHandshakeMessages  = MD5Core.GetHash(bAllHandshakeData);
                byte[]      bsha1OfHandshakeMessages = sha1.ComputeHash(bAllHandshakeData);
                ByteBuffer  bSum = new ByteBuffer();
                bSum.AppendData(bmd5OfHandshakeMessages);
                bSum.AppendData(bsha1OfHandshakeMessages);

                byte[] bCombinedHashes = bSum.GetAllSamples();

                /// No use in writing out this debug, only a few of the characters get seen, the rest are dropped
                ///System.Diagnostics.Debug.WriteLine("**** Start all handshake data ****\r\n{0}\r\n**** End all handshake data ****", ByteHelper.HexStringFromByte(bAllHandshakeData, true, 32));
                /// verify_data
                ///     PRF(master_secret, finished_label, MD5(handshake_messages) + SHA-1(handshake_messages)) [0..11];

                byte [] bComputedVerify = state.PRF(state.SecurityParameters.MasterSecret, "server finished", bCombinedHashes, 12);
                bool    bMatch          = ByteHelper.CompareArrays(msg.HandShakeFinished.verify_data, bComputedVerify);
                if (bMatch == false)
                {
                    SendAlert(AlertLevel.fatal, AlertDescription.HandshakeFailure);
                    Client.Disconnect();
                }
                else
                {
                    NegotiationFinished();
                }
            }
            else if (msg.HandShakeMessageType == HandShakeMessageType.CertificateRequest)
            {
                m_bSendClientCertificate = true;
            }



            if (ClientTLSState == TLS.ClientTLSState.ReceivedServerHello)
            {
                /// Gathering information
                ///
                if (msg.HandShakeMessageType == HandShakeMessageType.ServerHello)
                {
                    state.SecurityParameters.Cipher            = Cipher.FindCipher(msg.HandShakeServerHello.CipherSuite);
                    state.SecurityParameters.CompressionMethod = CompressionMethod.null0;
                    state.SecurityParameters.ConnectionEnd     = ConnectionEnd.client;
                    state.SecurityParameters.ServerRandom      = msg.HandShakeServerHello.RandomStruct.Bytes;
                }
                else if (msg.HandShakeMessageType == HandShakeMessageType.Certificate)
                {
                    if (msg.HandShakeCertificateMessage.Certificates.Count > 0)
                    {
                        state.SecurityParameters.PeerCertificate = msg.HandShakeCertificateMessage.Certificates[0];
                    }
                }
            }
        }
Esempio n. 2
0
        public TLSRecord DecompressRecord(TLSRecord record)
        {
            if (ReceiveEncryptionActive == false)
            {
                ReadSequenceNumber++;
                return(record);
            }

            /// Decompress, then verify hmac and seqnumber
            ///
            byte [] bFragment = null;
            byte [] bMAC      = null;

            byte [] bCipherTextBlock = record.RawSetContent;
            /// Store the cipher text block so we can use it as the next IV  (last block from the previous record)
            ///
            if (record.RawSetContent.Length > SecurityParameters.Cipher.BlockSizeBytes)
            {
                bCipherTextBlock = new byte[SecurityParameters.Cipher.BlockSizeBytes];
                Array.Copy(record.RawSetContent, record.RawSetContent.Length - SecurityParameters.Cipher.BlockSizeBytes, bCipherTextBlock, 0, SecurityParameters.Cipher.BlockSizeBytes);
            }

            DecryptRecord(record.RawSetContent, out bFragment, out bMAC);

            record.RawSetContent = bFragment;

            /// Compute the MAC ourselves so we can see if the man is correct
            ///Encrypt the compressed data.  The new data is now the encrypted data + a MAC.
            /// Compute the MAC before encrypting
            ///

            ///   The MAC is generated as:
            ///    HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
            ///                  TLSCompressed.version + TLSCompressed.length +
            ///                  TLSCompressed.fragment));
            /// where "+" denotes concatenation.
            ///
            byte[] bTLSRecord      = record.BytesFromRawContent;
            byte[] bDataToBeHashed = new byte[8 + bTLSRecord.Length];
            byte[] bSequence       = new byte[8];
            bSequence[0] = (byte)((ReadSequenceNumber & 0xFF00000000000000) >> 56);
            bSequence[1] = (byte)((ReadSequenceNumber & 0x00FF000000000000) >> 48);
            bSequence[2] = (byte)((ReadSequenceNumber & 0x0000FF0000000000) >> 40);
            bSequence[3] = (byte)((ReadSequenceNumber & 0x000000FF00000000) >> 32);
            bSequence[4] = (byte)((ReadSequenceNumber & 0x00000000FF000000) >> 24);
            bSequence[5] = (byte)((ReadSequenceNumber & 0x0000000000FF0000) >> 16);
            bSequence[6] = (byte)((ReadSequenceNumber & 0x000000000000FF00) >> 08);
            bSequence[7] = (byte)((ReadSequenceNumber & 0x00000000000000FF) >> 00);
            Array.Copy(bSequence, 0, bDataToBeHashed, 0, 8);
            Array.Copy(bTLSRecord, 0, bDataToBeHashed, 8, bTLSRecord.Length);

            byte[] bMACComputed = ServerHMAC.ComputeHash(bDataToBeHashed);
            ReadSequenceNumber++;
            LastCipherTextBlock = bCipherTextBlock;

            if (ByteHelper.CompareArrays(bMAC, bMACComputed) == false)
            {
                System.Threading.Thread.Sleep(0);
                //throw new Exception("Computed MAC did not match incoming record's MAC");
            }


            return(record);
        }