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); }
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); }
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); }
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); }
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)); } }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
public SslException(string inputMessage, Ssl.SslErrorCode error) : this(inputMessage, (int)error) { }
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); }
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); }