Exemplo n.º 1
0
        internal static int Decrypt(SafeSslHandle context, Span <byte> buffer, out Ssl.SslErrorCode errorCode)
        {
#if DEBUG
            ulong assertNoError = Crypto.ErrPeekError();
            Debug.Assert(assertNoError == 0, $"OpenSsl error queue is not empty, run: 'openssl errstr {assertNoError:X}' for original error.");
#endif
            BioWrite(context.InputBio !, buffer);

            int retVal = Ssl.SslRead(context, ref MemoryMarshal.GetReference(buffer), buffer.Length, out errorCode);
            if (retVal > 0)
            {
                return(retVal);
            }

            switch (errorCode)
            {
            // indicate end-of-file
            case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                break;

            case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ
                errorCode = Ssl.IsSslRenegotiatePending(context) ?
                            Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE :
                            Ssl.SslErrorCode.SSL_ERROR_WANT_READ;
                break;

            default:
                throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), GetSslError(retVal, errorCode));
            }

            return(0);
        }
Exemplo n.º 2
0
        private static Ssl.SslErrorCode GetSslError(SafeSslHandle context, int result, out Exception?innerError)
        {
            ErrorInfo lastErrno = Sys.GetLastErrorInfo(); // cache it before we make more P/Invoke calls, just in case we need it

            Ssl.SslErrorCode retVal = Ssl.SslGetError(context, result);
            switch (retVal)
            {
            case Ssl.SslErrorCode.SSL_ERROR_SYSCALL:
                // Some I/O error occurred
                innerError =
                    Crypto.ErrPeekError() != 0 ? Crypto.CreateOpenSslCryptographicException() :                                           // crypto error queue not empty
                    result == 0 ? new EndOfStreamException() :                                                                            // end of file that violates protocol
                    result == -1 && lastErrno.Error != Error.SUCCESS ? new IOException(lastErrno.GetErrorMessage(), lastErrno.RawErrno) : // underlying I/O error
                    null;                                                                                                                 // no additional info available
                break;

            case Ssl.SslErrorCode.SSL_ERROR_SSL:
                // OpenSSL failure occurred.  The error queue contains more details, when building the exception the queue will be cleared.
                innerError = Interop.Crypto.CreateOpenSslCryptographicException();
                break;

            default:
                // No additional info available.
                innerError = null;
                break;
            }
            return(retVal);
        }
Exemplo n.º 3
0
 private static Ssl.SslErrorCode GetSslError(SafeSslHandle context, int result)
 {
     Ssl.SslErrorCode retVal = Ssl.SslGetError(context, result);
     if (retVal == Ssl.SslErrorCode.SSL_ERROR_SYSCALL)
     {
         retVal = (Ssl.SslErrorCode)Crypto.ErrGetError();
     }
     return(retVal);
 }
Exemplo n.º 4
0
        internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int recvOffset, int recvCount, out byte[] sendBuf, out int sendCount)
        {
            sendBuf   = null;
            sendCount = 0;

            if ((recvBuf != null) && (recvCount > 0))
            {
                if (BioWrite(context.InputBio, recvBuf, recvOffset, recvCount) <= 0)
                {
                    // Make sure we clear out the error that is stored in the queue
                    throw Crypto.CreateOpenSslCryptographicException();
                }
            }

            int retVal = Ssl.SslDoHandshake(context);

            if (retVal != 1)
            {
                Exception        innerError;
                Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError);

                if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ))
                {
                    throw new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError);
                }
            }

            sendCount = Crypto.BioCtrlPending(context.OutputBio);
            if (sendCount > 0)
            {
                sendBuf = new byte[sendCount];

                try
                {
                    sendCount = BioRead(context.OutputBio, sendBuf, sendCount);
                }
                finally
                {
                    if (sendCount <= 0)
                    {
                        // Make sure we clear out the error that is stored in the queue
                        Crypto.ErrGetError();
                        sendBuf   = null;
                        sendCount = 0;
                    }
                }
            }

            bool stateOk = Ssl.IsSslStateOK(context);

            if (stateOk)
            {
                context.MarkHandshakeCompleted();
            }
            return(stateOk);
        }
Exemplo n.º 5
0
        private static SslException CreateSslException(string message, Ssl.SslErrorCode error)
        {
            string msg = SR.Format(message, error);

            switch (error)
            {
            case Ssl.SslErrorCode.SSL_ERROR_SYSCALL:
                return(CreateSslException(msg));

            case Ssl.SslErrorCode.SSL_ERROR_SSL:
                Exception innerEx = Interop.Crypto.CreateOpenSslCryptographicException();
                return(new SslException(innerEx.Message, innerEx));

            default:
                return(new SslException(msg, error));
            }
        }
Exemplo n.º 6
0
        internal static int Decrypt(SafeSslHandle context, Span <byte> buffer, out Ssl.SslErrorCode errorCode)
        {
            BioWrite(context.InputBio !, buffer);

            int retVal = Ssl.SslRead(context, ref MemoryMarshal.GetReference(buffer), buffer.Length, out errorCode);

            if (retVal > 0)
            {
                return(retVal);
            }

            switch (errorCode)
            {
            // indicate end-of-file
            case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                break;

            case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ
                errorCode = Ssl.IsSslRenegotiatePending(context)
                        ? Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE
                        : Ssl.SslErrorCode.SSL_ERROR_WANT_READ;
                break;

            case Ssl.SslErrorCode.SSL_ERROR_WANT_X509_LOOKUP:
                // This happens in TLS 1.3 when server requests post-handshake authentication
                // but no certificate is provided by client. We can process it the same way as
                // renegotiation on older TLS versions
                errorCode = Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE;
                break;

            default:
                throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), GetSslError(retVal, errorCode));
            }

            return(0);
        }
Exemplo n.º 7
0
        internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode)
        {
#if DEBUG
            ulong assertNoError = Crypto.ErrPeekError();
            Debug.Assert(assertNoError == 0, "OpenSsl error queue is not empty, run: 'openssl errstr " + assertNoError.ToString("X") + "' for original error.");
#endif
            errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

            int       retVal     = BioWrite(context.InputBio !, outBuffer, offset, count);
            Exception?innerError = null;

            if (retVal == count)
            {
                unsafe
                {
                    fixed(byte *fixedBuffer = outBuffer)
                    {
                        retVal = Ssl.SslRead(context, fixedBuffer + offset, outBuffer.Length);
                    }
                }

                if (retVal > 0)
                {
                    count = retVal;
                }
            }

            if (retVal != count)
            {
                errorCode = GetSslError(context, retVal, out innerError);
            }

            if (retVal != count)
            {
                retVal = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                    break;

                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ
                    errorCode = Ssl.IsSslRenegotiatePending(context) ?
                                Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE :
                                Ssl.SslErrorCode.SSL_ERROR_WANT_READ;
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError);
                }
            }

            return(retVal);
        }
Exemplo n.º 8
0
        internal static int Encrypt(SafeSslHandle context, ReadOnlySpan <byte> input, ref byte[] output, out Ssl.SslErrorCode errorCode)
        {
#if DEBUG
            ulong assertNoError = Crypto.ErrPeekError();
            Debug.Assert(assertNoError == 0, "OpenSsl error queue is not empty, run: 'openssl errstr " + assertNoError.ToString("X") + "' for original error.");
#endif
            errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

            int       retVal;
            Exception?innerError = null;

            retVal = Ssl.SslWrite(context, ref MemoryMarshal.GetReference(input), input.Length);

            if (retVal != input.Length)
            {
                errorCode = GetSslError(context, retVal, out innerError);
            }

            if (retVal != input.Length)
            {
                retVal = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError);
                }
            }
            else
            {
                int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio !);

                if (output == null || output.Length < capacityNeeded)
                {
                    output = new byte[capacityNeeded];
                }

                retVal = BioRead(context.OutputBio !, output, capacityNeeded);

                if (retVal <= 0)
                {
                    // Make sure we clear out the error that is stored in the queue
                    Crypto.ErrClearError();
                }
            }

            return(retVal);
        }
Exemplo n.º 9
0
        internal static bool DoSslHandshake(SafeSslHandle context, ReadOnlySpan <byte> input, out byte[]?sendBuf, out int sendCount)
        {
            sendBuf   = null;
            sendCount = 0;
            Exception?handshakeException = null;

            if (input.Length > 0)
            {
                if (Ssl.BioWrite(context.InputBio !, ref MemoryMarshal.GetReference(input), input.Length) != input.Length)
                {
                    // Make sure we clear out the error that is stored in the queue
                    throw Crypto.CreateOpenSslCryptographicException();
                }
            }

            int retVal = Ssl.SslDoHandshake(context);

            if (retVal != 1)
            {
                Exception?       innerError;
                Ssl.SslErrorCode error = GetSslError(context, retVal, out innerError);

                if ((retVal != -1) || (error != Ssl.SslErrorCode.SSL_ERROR_WANT_READ))
                {
                    // Handshake failed, but even if the handshake does not need to read, there may be an Alert going out.
                    // To handle that we will fall-through the block below to pull it out, and we will fail after.
                    handshakeException = new SslException(SR.Format(SR.net_ssl_handshake_failed_error, error), innerError);
                    Crypto.ErrClearError();
                }
            }

            sendCount = Crypto.BioCtrlPending(context.OutputBio !);
            if (sendCount > 0)
            {
                sendBuf = new byte[sendCount];

                try
                {
                    sendCount = BioRead(context.OutputBio !, sendBuf, sendCount);
                }
                catch (Exception) when(handshakeException != null)
                {
                    // If we already have handshake exception, ignore any exception from BioRead().
                }
                finally
                {
                    if (sendCount <= 0)
                    {
                        // Make sure we clear out the error that is stored in the queue
                        Crypto.ErrClearError();
                        sendBuf   = null;
                        sendCount = 0;
                    }
                }
            }

            if (handshakeException != null)
            {
                throw handshakeException;
            }

            bool stateOk = Ssl.IsSslStateOK(context);

            if (stateOk)
            {
                context.MarkHandshakeCompleted();
            }
            return(stateOk);
        }
Exemplo n.º 10
0
        internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int count, out Ssl.SslErrorCode errorCode)
        {
            errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

            int retVal = BioWrite(context.InputBio, outBuffer, 0, count);

            if (retVal == count)
            {
                retVal = Ssl.SslRead(context, outBuffer, outBuffer.Length);

                if (retVal > 0)
                {
                    count = retVal;
                }
            }

            if (retVal != count)
            {
                Exception innerError;
                errorCode = GetSslError(context, retVal, out innerError);
                retVal    = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                    break;

                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    // update error code to renegotiate if renegotiate is pending, otherwise make it SSL_ERROR_WANT_READ
                    errorCode = Ssl.IsSslRenegotiatePending(context) ?
                                Ssl.SslErrorCode.SSL_ERROR_RENEGOTIATE :
                                Ssl.SslErrorCode.SSL_ERROR_WANT_READ;
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_decrypt_failed, errorCode), innerError);
                }
            }

            return(retVal);
        }
Exemplo n.º 11
0
        internal static int Encrypt(SafeSslHandle context, byte[] buffer, int offset, int count, out Ssl.SslErrorCode errorCode)
        {
            Debug.Assert(buffer != null);
            Debug.Assert(offset >= 0);
            Debug.Assert(count >= 0);
            Debug.Assert(buffer.Length >= offset + count);

            errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

            int retVal;

            unsafe
            {
                fixed(byte *fixedBuffer = buffer)
                {
                    retVal = Ssl.SslWrite(context, fixedBuffer + offset, count);
                }
            }

            if (retVal != count)
            {
                Exception innerError;
                errorCode = GetSslError(context, retVal, out innerError);
                retVal    = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError);
                }
            }
            else
            {
                int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio);

                Debug.Assert(buffer.Length >= capacityNeeded, "Input buffer of size " + buffer.Length +
                             " bytes is insufficient since encryption needs " + capacityNeeded + " bytes.");

                retVal = BioRead(context.OutputBio, buffer, capacityNeeded);
            }

            return(retVal);
        }
Exemplo n.º 12
0
        internal static int Encrypt(SafeSslHandle context, ReadOnlyMemory <byte> input, ref byte[] output, out Ssl.SslErrorCode errorCode)
        {
            errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

            int retVal;

            unsafe
            {
                using (MemoryHandle handle = input.Pin())
                {
                    retVal = Ssl.SslWrite(context, (byte *)handle.Pointer, input.Length);
                }
            }

            if (retVal != input.Length)
            {
                errorCode = GetSslError(context, retVal, out Exception innerError);
                retVal    = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError);
                }
            }
            else
            {
                int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio);

                if (output == null || output.Length < capacityNeeded)
                {
                    output = new byte[capacityNeeded];
                }

                retVal = BioRead(context.OutputBio, output, capacityNeeded);
                if (retVal <= 0)
                {
                    // Make sure we clear out the error that is stored in the queue
                    Crypto.ErrGetError();
                }
            }

            return(retVal);
        }
Exemplo n.º 13
0
 public SslException(string inputMessage, Ssl.SslErrorCode error)
     : this(inputMessage, (int)error)
 {
 }
Exemplo n.º 14
0
        internal static int Encrypt(SafeSslHandle context, byte[] input, int offset, int count, ref byte[] output, out Ssl.SslErrorCode errorCode)
        {
            Debug.Assert(input != null);
            Debug.Assert(offset >= 0);
            Debug.Assert(count >= 0);
            Debug.Assert(offset <= input.Length);
            Debug.Assert(input.Length - offset >= count);

            errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;

            int retVal;

            unsafe
            {
                fixed(byte *fixedBuffer = input)
                {
                    retVal = Ssl.SslWrite(context, fixedBuffer + offset, count);
                }
            }

            if (retVal != count)
            {
                Exception innerError;
                errorCode = GetSslError(context, retVal, out innerError);
                retVal    = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), innerError);
                }
            }
            else
            {
                int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio);

                if (output == null || output.Length < capacityNeeded)
                {
                    output = new byte[capacityNeeded];
                }

                retVal = BioRead(context.OutputBio, output, capacityNeeded);
            }

            return(retVal);
        }
Exemplo n.º 15
0
        internal static int Encrypt(SafeSslHandle context, ReadOnlySpan <byte> input, ref byte[] output, out Ssl.SslErrorCode errorCode)
        {
            int retVal = Ssl.SslWrite(context, ref MemoryMarshal.GetReference(input), input.Length, out errorCode);

            if (retVal != input.Length)
            {
                retVal = 0;

                switch (errorCode)
                {
                // indicate end-of-file
                case Ssl.SslErrorCode.SSL_ERROR_ZERO_RETURN:
                case Ssl.SslErrorCode.SSL_ERROR_WANT_READ:
                    break;

                default:
                    throw new SslException(SR.Format(SR.net_ssl_encrypt_failed, errorCode), GetSslError(retVal, errorCode));
                }
            }
            else
            {
                int capacityNeeded = Crypto.BioCtrlPending(context.OutputBio !);

                if (output == null || output.Length < capacityNeeded)
                {
                    output = new byte[capacityNeeded];
                }

                retVal = BioRead(context.OutputBio !, output, capacityNeeded);

                if (retVal <= 0)
                {
                    // Make sure we clear out the error that is stored in the queue
                    Crypto.ErrClearError();
                }
            }

            return(retVal);
        }