Beispiel #1
0
        /// <devdoc>
        ///    <para>
        ///       Performs encryption of an array of buffers,
        ///         proceeds buffer by buffer, if the individual
        ///         buffer size exceeds a SSL limit of 64K,
        ///         the buffers are then split into smaller ones.
        ///       Returns a new array of encrypted buffers.
        ///    </para>
        /// </devdoc>
        private BufferOffsetSize [] EncryptBuffers(BufferOffsetSize[] buffers)
        {
            // do we need lock this write as well?
            ArrayList encryptedBufferList = new ArrayList(buffers.Length);

            for (int i = 0; i < buffers.Length; i++)
            {
                SecureChannel chkSecureChannel = SecureChannel;
                if (chkSecureChannel == null)
                {
                    InnerException = new IOException(SR.GetString(SR.net_io_writefailure));
                    throw InnerException;
                }

                int offset    = buffers[i].Offset;
                int totalLeft = buffers[i].Size;
                do
                {
                    byte [] tempOutput = null;
                    int     size       = Math.Min(totalLeft, chkSecureChannel.MaxDataSize);

                    totalLeft -= size;

                    int errorCode = chkSecureChannel.Encrypt(buffers[i].Buffer, offset, size, ref tempOutput);

                    if (errorCode != (int)SecurityStatus.OK)
                    {
                        ProtocolToken message = new ProtocolToken(null, errorCode);
                        InnerException = message.GetException();
                        throw InnerException;
                    }

                    encryptedBufferList.Add(new BufferOffsetSize(tempOutput, false));

                    offset += size;
                } while (totalLeft > 0);
            }
            return((BufferOffsetSize [])encryptedBufferList.ToArray(typeof(BufferOffsetSize)));
        }
Beispiel #2
0
        //
        // Handshake - the Handshake is perhaps the most important part of the SSL process,
        //  this is a Handshake protocol between server & client, where we send a
        //  a HELLO message / server responds, we respond back, and after a few round trips,
        //  we have an SSL connection with the server.  But this process may be repeated,
        //  if a higher level of security is required for by the server, therefore,
        //  this function may be called several times in the life of the connection.
        //
        //  returns an Exception on error, containing the error code of the failure
        //

        private Exception Handshake(ProtocolToken message)
        {
            //
            // With some SSPI APIs, the SSPI wrapper may throw
            //  uncaught Win32Exceptions, so we need to add
            //  this try - catch here.
            //

            try {
                int    round    = 0;
                byte[] incoming = null;

                // will be null == message on connection creation/otherwise should be
                //  renegotation

                if (message == null)
                {
                    GlobalLog.Assert(
                        (SecureChannel == null),
                        "had assembed a null SecureChannel at this point",
                        "SecureChannel != null");

                    m_SecureChannel = new SecureChannel(m_DestinationHost, m_ClientCertificates);
                }
                else
                {
                    incoming = message.Payload;
                }

                do
                {
                    GlobalLog.Print("Handshake::Round #" + round);

                    //
                    // this code runs in the constructor, hence there's no
                    // way SecureChannel can become null
                    //
                    message = SecureChannel.NextMessage(incoming);

#if TRAVE
                    GlobalLog.Print("Handshake::generating TLS message(Status:" + SecureChannel.MapSecurityStatus((uint)message.Status) + " Done:" + message.Done.ToString() + ")");
#endif

                    if (message.Failed)
                    {
                        break;
                    }

                    if (message.Payload != null)
                    {
                        GlobalLog.Print("Handshake::Outgoing message size: " + message.Payload.Length);
                        GlobalLog.Dump(message.Payload);
                        base.Write(message.Payload, 0, message.Payload.Length);
                    }
                    else
                    {
                        GlobalLog.Print("Handshake::No message necessary.");
                    }

                    if (message.Done)
                    {
                        break;
                    }

                    //
                    // ReadFullRecord attempts to parse read data
                    //   from the byte stream, this can be dangerous as its not
                    //   always sure about protocols, at this point
                    //

                    incoming = ReadFullRecord(null, 0);

                    if (incoming == null)
                    {
                        //
                        // Handshake failed
                        //
                        GlobalLog.Print("Handshake::ReadFullRecord is null, Handshake failed");

                        GlobalLog.Assert(
                            (!message.Done),
                            "attempted bad return / must always fail",
                            "message.Done");

                        return(message.GetException());
                    }

                    GlobalLog.Print("Handshake::Incoming message size: " + incoming.Length);
                    round++;
                } while (!message.Done);

                if (message.Done)
                {
                    SecureChannel.ProcessHandshakeSuccess();
                    GlobalLog.Print("Handshake::Handshake completed successfully.");
                }
                else
                {
                    // SEC_I_CONTINUE_NEEDED
#if TRAVE
                    GlobalLog.Print("Handshake::FAILED Handshake, last error: " + SecureChannel.MapSecurityStatus((uint)message.Status));
#endif
                }
                return(message.GetException());
            }
            catch (Exception exception) {
                return(exception);
            }
        }
Beispiel #3
0
        private IAsyncResult InnerWrite(bool async, byte[] buffer, int offset, int size, AsyncCallback asyncCallback, object asyncState)
        {
            // after shutdown/Close throw an exception
            if (m_ShutDown > 0)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            // on earlier error throw an exception
            if (InnerException != null)
            {
                throw InnerException;
            }
            //
            // parameter validation
            //
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0 || offset > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (size < 0 || size > buffer.Length - offset)
            {
                throw new ArgumentOutOfRangeException("size");
            }


            //
            // Lock the Write: this is inefficent, but we need to prevent
            //  writing data while the Stream is doing a handshake with the server.
            //  writing other data during the handshake would cause the server to
            //  fail and close the connection.
            //

            lock (this) {
                //
                // encrypt the data
                //

                byte[] ciphertext = null;

                GlobalLog.Print("Encrypt[" + Encoding.ASCII.GetString(buffer, 0, Math.Min(buffer.Length, 512)) + "]");

                SecureChannel chkSecureChannel = SecureChannel;
                if (chkSecureChannel == null)
                {
                    InnerException = new IOException(SR.GetString(SR.net_io_writefailure));
                    throw InnerException;
                }

                if (size > chkSecureChannel.MaxDataSize)
                {
                    BufferOffsetSize [] buffers = new BufferOffsetSize[1];
                    buffers[0] = new BufferOffsetSize(buffer, offset, size, false);
                    if (async)
                    {
                        return(BeginMultipleWrite(buffers, asyncCallback, asyncState));
                    }
                    else
                    {
                        MultipleWrite(buffers);
                        return(null);
                    }
                }

                int errorCode = chkSecureChannel.Encrypt(buffer, offset, size, ref ciphertext);

                if (errorCode != (int)SecurityStatus.OK)
                {
                    ProtocolToken message = new ProtocolToken(null, errorCode);
                    InnerException = message.GetException();
                    throw InnerException;
                }

                try {
                    if (async)
                    {
                        IAsyncResult asyncResult =
                            base.BeginWrite(
                                ciphertext,
                                0,
                                ciphertext.Length,
                                asyncCallback,
                                asyncState);

                        return(asyncResult);
                    }
                    else
                    {
                        base.Write(ciphertext, 0, ciphertext.Length);
                        return(null);
                    }
                }
                catch (Exception exception) {
                    //
                    // some sort of error occured Writing to the Trasport,
                    // set the Exception as InnerException and throw
                    //
                    InnerException = new IOException(SR.GetString(SR.net_io_writefailure), exception);
                    throw InnerException;
                }
            }
        }
Beispiel #4
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;
        }