예제 #1
0
        //
        // NextRecord - called typically in Callback
        //  to indicate that we need more bytes from the wire
        //  to be decrypted.  It is called either by a worker
        //  thread or by the Read directly, it reads one chunk
        //  of data, and attempts to decrypt.  As soon as it has
        //  the chunk of unencrypted data, it returns it in
        //  m_ArrivingData and m_ExistingAmount contains,
        //  the amount data that was decrypted.
        //
        // ASSUMES: we have an empty buffer of unencrypted bytes
        // RETURNS: upon error, by either leaving this buffer empty (0),
        //   with an Exception set on this object, or on success,
        //   by updating the global state (m_ArrivingData)
        //   with unencrypted bytes
        //
        // WARNING: Can Throw!
        //
        private void NextRecord(byte[] buffer, int length)
        {
            byte[] packet = null;

            GlobalLog.Assert(
                (m_ExistingAmount == 0),
                "m_ExistingAmount != 0",
                "Has assumed internal SSL buffer would be empty");

            //
            // This LOOP below will keep going until (EITHER):
            //   1) we have ONE succesful chunk of unencrypted data
            //   2) we have an error either from a renegotiate handhake (OR) Read (OR) Decrypt
            //

            do
            {
                packet = ReadFullRecord(buffer, length);

                if (packet == null)
                {
                    return;
                }

                lock (this) {
                    SecureChannel chkSecureChannel = SecureChannel;
                    if (chkSecureChannel == null)
                    {
                        return;
                    }

                    int errorCode = chkSecureChannel.Decrypt(packet, ref m_ArrivingData);

                    if (errorCode == (int)SecurityStatus.OK)
                    {
                        // SUCCESS - we have our decrypted Bytes

                        GlobalLog.Print("TlsStream::NextRecord called (success) Decrypt["
                                        + (m_ArrivingData != null
                                ? (Encoding.ASCII.GetString(m_ArrivingData, 0, Math.Min(m_ArrivingData.Length, 512)))
                                : "null")
                                        + "]");
                        break;
                    }
                    else
                    {
                        // ERROR - examine what kind

                        ProtocolToken message = new ProtocolToken(packet, errorCode);

                        GlobalLog.Print("TlsStream:: Decrypt errorCode = " + errorCode.ToString());

                        if (message.Renegotiate)
                        {
                            // HANDSHAKE - do a handshake between us and server

                            InnerException = Handshake(message);
                            if (InnerException != null)
                            {
                                return; // failure
                            }

                            // CONTINUE - Read On! we pick up from where
                            //  we were before the handshake and try to get
                            //  one block of unencrypted bytes, the earlier block
                            //  of data was control information for the handshake.

                            //  We need to read in the new header.
                            if (ForceRead(buffer, 0, length) < length)
                            {
                                InnerException = new IOException(SR.GetString(SR.net_io_readfailure));
                                return; //failure
                            }
                        }
                        else if (message.CloseConnection)
                        {
                            // CLOSE - server ordered us to shut down

                            Close(); // close down the socket
                            return;
                        }
                        else
                        {
                            // EXCEPTION - throw later on

                            InnerException = message.GetException();
                            return;
                        }
                    }
                }

                // continue here in the case where we had a handshake, and needed
                //  to reget new Data
            } while (true);

            // m_ExistingAmount was 0 on entry!

            if (m_ArrivingData == null)
            {
                return;
            }

            m_ExistingAmount = m_ArrivingData.Length;

            return;
        }