Example #1
0
        //
        // Only processing SEC_I_RENEGOTIATE.
        //
        private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer)
        {
            ProtocolToken message = new ProtocolToken(null, status);

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString());
            }

            if (message.Renegotiate)
            {
                _sslState.ReplyOnReAuthentication(extraBuffer);

                // Loop on read.
                return(-1);
            }

            if (message.CloseConnection)
            {
                _sslState.FinishRead(null);
                if (asyncRequest != null)
                {
                    asyncRequest.CompleteUser((object)0);
                }

                return(0);
            }

            throw new IOException(SR.net_io_decrypt, message.GetException());
        }
Example #2
0
        internal static SecurityStatusPal InitializeSecurityContext(
            ref SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext?securityContext,
            string?spn,
            ContextFlagsPal requestedContextFlags,
            ReadOnlySpan <byte> incomingBlob,
            ChannelBinding?channelBinding,
            ref byte[]?resultBlob,
            out int resultBlobLength,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                channelBinding,
                spn,
                requestedContextFlags,
                incomingBlob,
                out resultBlob,
                ref contextFlags);

            resultBlobLength = resultBlob?.Length ?? 0;

            return(status);
        }
Example #3
0
        //
        // Only processing SEC_I_RENEGOTIATE.
        //
        private int ProcessReadErrorCode(SecurityStatusPal errorCode, byte[] buffer, int offset, int count, byte[] extraBuffer)
        {
            // ERROR - examine what kind
            ProtocolToken message = new ProtocolToken(null, errorCode);

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString());
            }

            if (message.Renegotiate)
            {
                _SslState.ReplyOnReAuthentication(extraBuffer);

                // Loop on read.
                return(-1);
            }

            if (message.CloseConnection)
            {
                _SslState.FinishRead(null);
                return(0);
            }

            throw new IOException(SR.net_io_decrypt, message.GetException());
        }
Example #4
0
        private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer)
        {
            ProtocolToken message = new ProtocolToken(null, status);

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(null, $"***Processing an error Status = {message.Status}");
            }

            if (message.Renegotiate)
            {
                _sslState.ReplyOnReAuthentication(extraBuffer);

                // Loop on read.
                return(-1);
            }

            if (message.CloseConnection)
            {
                _sslState.FinishRead(null);
                asyncRequest?.CompleteUser(0);

                return(0);
            }

            throw new IOException(SR.net_io_decrypt, message.GetException());
        }
        //
        // Client side starts here, but server also loops through this method.
        //
        private void SendBlob(byte[] incoming, int count)
        {
            ProtocolToken message = _context.NextMessage(incoming, 0, count);

            _securityStatus = message.Status;

            if (message.Size != 0)
            {
                if (_context.IsServer && _CachedSession == CachedSessionStatus.Unknown)
                {
                    //
                    //[Schannel] If the first call to ASC returns a token less than 200 bytes,
                    //           then it's a reconnect (a handshake based on a cache entry).
                    //
                    _CachedSession = message.Size < 200 ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached;
                }

                if (_framing == Framing.Unified)
                {
                    _framing = DetectFraming(message.Payload, message.Payload.Length);
                }

                InnerStream.Write(message.Payload, 0, message.Size);
            }

            CheckCompletionBeforeNextReceive(message);
        }
Example #6
0
        //
        // readBytes == SSL Data Payload size on input or 0 on EOF.
        //
        private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            if (readBytes == 0)
            {
                // EOF
                throw new IOException(SR.net_io_eof);
            }

            // Set readBytes to total number of received bytes.
            readBytes += SecureChannel.ReadHeaderSize;

            // Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_.
            int data_offset = 0;

            SecurityStatusPal status = _sslState.DecryptData(InternalBuffer, ref data_offset, ref readBytes);

            if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
            {
                byte[] extraBuffer = null;
                if (readBytes != 0)
                {
                    extraBuffer = new byte[readBytes];
                    Buffer.BlockCopy(InternalBuffer, data_offset, extraBuffer, 0, readBytes);
                }

                // Reset internal buffer count.
                SkipBytes(InternalBufferCount);
                return(ProcessReadErrorCode(status, buffer, offset, count, asyncRequest, extraBuffer));
            }


            if (readBytes == 0 && count != 0)
            {
                // Read again since remote side has sent encrypted 0 bytes.
                SkipBytes(InternalBufferCount);
                return(-1);
            }

            // Decrypted data start from "data_offset" offset, the total count can be shrunk after decryption.
            EnsureInternalBufferSize(0, data_offset + readBytes);
            SkipBytes(data_offset);

            if (readBytes > count)
            {
                readBytes = count;
            }

            Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, readBytes);

            // This will adjust both the remaining internal buffer count and the offset.
            SkipBytes(readBytes);

            _sslState.FinishRead(null);
            if (asyncRequest != null)
            {
                asyncRequest.CompleteUser((object)readBytes);
            }

            return(readBytes);
        }
Example #7
0
        /// <summary>
        /// Generate SSPI context
        /// </summary>
        /// <param name="handle">SNI connection handle</param>
        /// <param name="receivedBuff">Receive buffer</param>
        /// <param name="receivedLength">Received length</param>
        /// <param name="sendBuff">Send buffer</param>
        /// <param name="sendLength">Send length</param>
        /// <param name="serverName">Service Principal Name buffer</param>
        /// <param name="serverNameLength">Length of Service Principal Name</param>
        /// <returns>SNI error code</returns>
        public void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[] serverName)
        {
            SafeDeleteContext   securityContext   = sspiClientContextStatus.SecurityContext;
            ContextFlagsPal     contextFlags      = sspiClientContextStatus.ContextFlags;
            SafeFreeCredentials credentialsHandle = sspiClientContextStatus.CredentialsHandle;

            SecurityBuffer[] inSecurityBufferArray = null;
            if (securityContext == null) //first iteration
            {
                credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(Kerberos, false);
            }
            else
            {
                inSecurityBufferArray = new SecurityBuffer[] { new SecurityBuffer(receivedBuff, SecurityBufferType.SECBUFFER_TOKEN) };
            }

            int            tokenSize         = NegotiateStreamPal.QueryMaxTokenSize(Kerberos);
            SecurityBuffer outSecurityBuffer = new SecurityBuffer(tokenSize, SecurityBufferType.SECBUFFER_TOKEN);

            ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection
                                                    | ContextFlagsPal.Confidentiality
                                                    | ContextFlagsPal.MutualAuth;

            string serverSPN = System.Text.Encoding.UTF8.GetString(serverName);

            SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext(
                credentialsHandle,
                ref securityContext,
                serverSPN,
                requestedContextFlags,
                inSecurityBufferArray,
                outSecurityBuffer,
                ref contextFlags);

            if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded ||
                statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue)
            {
                inSecurityBufferArray = new SecurityBuffer[] { outSecurityBuffer };
                statusCode            = NegotiateStreamPal.CompleteAuthToken(ref securityContext, inSecurityBufferArray);
            }

            sendBuff = outSecurityBuffer.token;

            sspiClientContextStatus.SecurityContext   = securityContext;
            sspiClientContextStatus.ContextFlags      = contextFlags;
            sspiClientContextStatus.CredentialsHandle = credentialsHandle;

            if (IsErrorStatus(statusCode.ErrorCode))
            {
                if (statusCode.ErrorCode == SecurityStatusPalErrorCode.InternalError &&
                    statusCode.Exception is Interop.NetSecurityNative.GssApiException) // when unable to access Kerberos Ticket
                {
                    throw new Exception(SQLMessage.KerberosTicketMissingError() + "\n" + statusCode);
                }
                else
                {
                    throw new Exception(SQLMessage.SSPIGenerateError() + "\n" + statusCode);
                }
            }
        }
Example #8
0
        /*++
         *  Encrypt - Encrypts our bytes before we send them over the wire
         *
         *  PERF: make more efficient, this does an extra copy when the offset
         *  is non-zero.
         *
         *  Input:
         *      buffer - bytes for sending
         *      offset -
         *      size   -
         *      output - Encrypted bytes
         * --*/
        internal SecurityStatusPal Encrypt(byte[] buffer, int offset, int size, ref byte[] output, out int resultSize)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::Encrypt");
            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() - offset: " + offset.ToString() + " size: " + size.ToString() + " buffersize: " + buffer.Length.ToString());
            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Encrypt() buffer:");
            GlobalLog.Dump(buffer, Math.Min(buffer.Length, 128));

            byte[] writeBuffer;
            try
            {
                if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length))
                {
                    throw new ArgumentOutOfRangeException("offset");
                }

                if (size < 0 || size > (buffer == null ? 0 : buffer.Length - offset))
                {
                    throw new ArgumentOutOfRangeException("size");
                }

                resultSize = 0;

                int bufferSizeNeeded = checked (size + _headerSize + _trailerSize);
                if (output != null && bufferSizeNeeded <= output.Length)
                {
                    writeBuffer = output;
                }
                else
                {
                    writeBuffer = new byte[bufferSizeNeeded];
                }

                Buffer.BlockCopy(buffer, offset, writeBuffer, _headerSize, size);
            }
            catch (Exception e)
            {
                if (!ExceptionCheck.IsFatal(e))
                {
                    GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Arguments out of range.");
                }

                throw;
            }

            SecurityStatusPal secStatus = SslStreamPal.EncryptMessage(_securityContext, writeBuffer, size, _headerSize, _trailerSize, out resultSize);

            if (secStatus != SecurityStatusPal.OK)
            {
                GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt ERROR", secStatus.ToString());
            }
            else
            {
                output = writeBuffer;
                GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::Encrypt OK", "data size:" + resultSize.ToString());
            }

            return(secStatus);
        }
Example #9
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string[] spns,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            // TODO (Issue #3718): The second buffer can contain a channel binding which is not supported
            if ((null != inSecurityBufferArray) && (inSecurityBufferArray.Length > 1))
            {
                throw new PlatformNotSupportedException(Strings.net_nego_channel_binding_not_supported);
            }

            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;
            SecurityStatusPal       status = default;

            foreach (string spn in spns)
            {
                if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
                {
                    throw new PlatformNotSupportedException(Strings.net_nego_not_supported_empty_target_with_defaultcreds);
                }

                status = EstablishSecurityContext(
                    negoCredentialsHandle,
                    ref securityContext,
                    spn,
                    requestedContextFlags,
                    ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
                    outSecurityBuffer,
                    ref contextFlags);

                if (status.ErrorCode != SecurityStatusPalErrorCode.InternalError)
                {
                    break; // Successful case, exit the loop with current SPN.
                }
                else
                {
                    securityContext = null; // Reset security context to be generated again for next SPN.
                }
            }

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(Strings.net_nego_protection_level_not_supported);
                }
            }
            return(status);
        }
Example #10
0
        public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext, byte[] buffer, ref int offset, ref int count)
        {
            SecurityStatusPal retVal = EncryptDecryptHelper(securityContext, buffer, offset, count, false, ref buffer, out int resultSize);

            if (retVal.ErrorCode == SecurityStatusPalErrorCode.OK ||
                retVal.ErrorCode == SecurityStatusPalErrorCode.Renegotiate)
            {
                count = resultSize;
            }
            return(retVal);
        }
Example #11
0
        private static SecurityStatusPal HandshakeInternal(
            SafeFreeCredentials credential,
            ref SafeDeleteContext context,
            SecurityBuffer inputBuffer,
            SecurityBuffer outputBuffer,
            bool isServer,
            bool remoteCertRequired,
            string targetName)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)context);

                if ((null == context) || context.IsInvalid)
                {
                    sslContext = new SafeDeleteSslContext(credential as SafeFreeSslCredentials, isServer);
                    context    = sslContext;

                    if (!string.IsNullOrEmpty(targetName))
                    {
                        Debug.Assert(!isServer, "targetName should not be set for server-side handshakes");
                        Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, targetName);
                    }

                    if (remoteCertRequired)
                    {
                        Debug.Assert(isServer, "remoteCertRequired should not be set for client-side handshakes");
                        Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext);
                    }
                }

                if (inputBuffer != null && inputBuffer.size > 0)
                {
                    sslContext.Write(inputBuffer.token, inputBuffer.offset, inputBuffer.size);
                }

                SecurityStatusPal status = PerformHandshake(sslContext.SslContext);

                byte[] output = sslContext.ReadPendingWrites();
                outputBuffer.offset = 0;
                outputBuffer.size   = output?.Length ?? 0;
                outputBuffer.token  = output;

                return(status);
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }
Example #12
0
        private static SecurityStatusPal HandshakeInternal(
            SafeFreeCredentials credential,
            ref SafeDeleteSslContext?context,
            ReadOnlySpan <byte> inputBuffer,
            ref byte[]?outputBuffer,
            SslAuthenticationOptions sslAuthenticationOptions,
            SelectClientCertificate?clientCertificateSelectionCallback)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context);

                if ((null == context) || context.IsInvalid)
                {
                    sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions);
                    context    = sslContext;
                }

                if (inputBuffer.Length > 0)
                {
                    sslContext !.Write(inputBuffer);
                }

                SafeSslHandle     sslHandle = sslContext !.SslContext;
                SecurityStatusPal status    = PerformHandshake(sslHandle);
                if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded && clientCertificateSelectionCallback != null)
                {
                    X509Certificate2?clientCertificate = clientCertificateSelectionCallback(out bool _);
                    if (clientCertificate != null)
                    {
                        sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate);
                        SafeDeleteSslContext.SetCertificate(sslContext.SslContext, sslAuthenticationOptions.CertificateContext);
                    }

                    // We either got certificate or we can proceed without it. It is up to the server to decide if either is OK.
                    status = PerformHandshake(sslHandle);
                }

                outputBuffer = sslContext.ReadPendingWrites();
                return(status);
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }
Example #13
0
        private static SecurityStatusPal HandshakeInternal(
            SafeFreeCredentials credential,
            ref SafeDeleteSslContext?context,
            ReadOnlySpan <byte> inputBuffer,
            ref byte[]?outputBuffer,
            SslAuthenticationOptions sslAuthenticationOptions)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context);

                if ((null == context) || context.IsInvalid)
                {
                    sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions);
                    context    = sslContext;

                    if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost))
                    {
                        Debug.Assert(!sslAuthenticationOptions.IsServer, "targetName should not be set for server-side handshakes");
                        Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, sslAuthenticationOptions.TargetHost);
                    }

                    if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired)
                    {
                        Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext);
                    }
                }

                if (inputBuffer.Length > 0)
                {
                    sslContext !.Write(inputBuffer);
                }

                SafeSslHandle     sslHandle = sslContext !.SslContext;
                SecurityStatusPal status    = PerformHandshake(sslHandle);

                outputBuffer = sslContext.ReadPendingWrites();
                return(status);
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }
Example #14
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string spn,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityBuffer cbtBuffer = null;

            if ((inSecurityBufferArray != null) && (inSecurityBufferArray.Length > 1))
            {
                Debug.Assert(inSecurityBufferArray[1].type == SecurityBufferType.SECBUFFER_CHANNEL_BINDINGS);
                cbtBuffer = inSecurityBufferArray[1];
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                cbtBuffer,
                spn,
                requestedContextFlags,
                ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
                outSecurityBuffer,
                ref contextFlags);

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported);
                }
            }

            return(status);
        }
Example #15
0
        //
        // readBytes == SSL Data Payload size on input or 0 on EOF.
        //
        private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            if (readBytes == 0)
            {
                // EOF
                throw new IOException(SR.net_io_eof);
            }

            // At this point, readBytes contains the size of the header plus body.
            // Set _decrytpedBytesOffset/Count to the current frame we have (including header)
            // DecryptData will decrypt in-place and modify these to point to the actual decrypted data, which may be smaller.
            _decryptedBytesOffset = _internalOffset;
            _decryptedBytesCount  = readBytes;
            SecurityStatusPal status = _sslState.DecryptData(_internalBuffer, ref _decryptedBytesOffset, ref _decryptedBytesCount);

            // Treat the bytes we just decrypted as consumed
            // Note, we won't do another buffer read until the decrypted bytes are processed
            ConsumeBufferedBytes(readBytes);

            if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
            {
                byte[] extraBuffer = null;
                if (_decryptedBytesCount != 0)
                {
                    extraBuffer = new byte[_decryptedBytesCount];
                    Buffer.BlockCopy(_internalBuffer, _decryptedBytesOffset, extraBuffer, 0, _decryptedBytesCount);

                    _decryptedBytesCount = 0;
                }

                return(ProcessReadErrorCode(status, asyncRequest, extraBuffer));
            }

            if (_decryptedBytesCount == 0)
            {
                // Read again since remote side has sent encrypted 0 bytes.
                return(-1);
            }

            int copyBytes = CopyDecryptedData(buffer, offset, count);

            _sslState.FinishRead(null);
            asyncRequest?.CompleteUser(copyBytes);

            return(copyBytes);
        }
Example #16
0
        //
        internal ProtocolToken NextMessage(byte[] incoming, int offset, int count)
        {
            GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::NextMessage");
            byte[]            nextmsg   = null;
            SecurityStatusPal errorCode = GenerateToken(incoming, offset, count, ref nextmsg);

            if (!_serverMode && errorCode == SecurityStatusPal.CredentialsNeeded)
            {
                GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::NextMessage() returned SecurityStatusPal.CredentialsNeeded");
                SetRefreshCredentialNeeded();
                errorCode = GenerateToken(incoming, offset, count, ref nextmsg);
            }

            ProtocolToken token = new ProtocolToken(nextmsg, errorCode);

            GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::NextMessage", token.ToString());
            return(token);
        }
Example #17
0
        internal SecurityStatusPal Decrypt(byte[] payload, ref int offset, ref int count)
        {
            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::Decrypt() - offset: " + offset.ToString() + " size: " + count.ToString() + " buffersize: " + payload.Length.ToString());

            if (offset < 0 || offset > (payload == null ? 0 : payload.Length))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset");
            }

            if (count < 0 || count > (payload == null ? 0 : payload.Length - offset))
            {
                GlobalLog.Assert(false, "SecureChannel#" + Logging.HashString(this) + "::Encrypt", "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count");
            }

            SecurityStatusPal secStatus = SslStreamPal.DecryptMessage(_securityContext, payload, ref offset, ref count);

            return(secStatus);
        }
Example #18
0
        public static SecurityStatusPal DecryptMessage(SafeDeleteSslContext securityContext, byte[] buffer, ref int offset, ref int count)
        {
            try
            {
                int resultSize = Interop.OpenSsl.Decrypt(securityContext.SslContext, new Span <byte>(buffer, offset, count), out Interop.Ssl.SslErrorCode errorCode);

                SecurityStatusPal retVal = MapNativeErrorCode(errorCode);

                if (retVal.ErrorCode == SecurityStatusPalErrorCode.OK ||
                    retVal.ErrorCode == SecurityStatusPalErrorCode.Renegotiate)
                {
                    count = resultSize;
                }

                return(retVal);
            }
            catch (Exception ex)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }
Example #19
0
        internal static SecurityStatusPal InitializeSecurityContext(
            ref SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext?securityContext,
            string?spn,
            ContextFlagsPal requestedContextFlags,
            byte[]?incomingBlob,
            ChannelBinding?channelBinding,
            ref byte[]?resultBlob,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                channelBinding,
                spn,
                requestedContextFlags,
                incomingBlob,
                ref resultBlob,
                ref contextFlags);

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported);
                }
            }

            return(status);
        }
Example #20
0
 public static Exception GetException(SecurityStatusPal status)
 {
     return status.Exception ?? new Interop.OpenSsl.SslException((int)status.ErrorCode);
 }
Example #21
0
        //
        // Client side starts here, but server also loops through this method.
        //
        private void StartSendBlob(byte[] incoming, int count, AsyncProtocolRequest asyncRequest)
        {
            ProtocolToken message = Context.NextMessage(incoming, 0, count);
            _securityStatus = message.Status;

            if (message.Size != 0)
            {
                if (Context.IsServer && _CachedSession == CachedSessionStatus.Unknown)
                {
                    //
                    //[Schannel] If the first call to ASC returns a token less than 200 bytes,
                    //           then it's a reconnect (a handshake based on a cache entry).
                    //
                    _CachedSession = message.Size < 200 ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached;
                }

                if (_Framing == Framing.Unified)
                {
                    _Framing = DetectFraming(message.Payload, message.Payload.Length);
                }

                if (asyncRequest == null)
                {
                    InnerStream.Write(message.Payload, 0, message.Size);
                }
                else
                {
                    asyncRequest.AsyncState = message;
                    IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest);
                    if (!ar.CompletedSynchronously)
                    {
#if DEBUG
                        asyncRequest._DebugAsyncChain = ar;
#endif
                        return;
                    }

                    InnerStreamAPM.EndWrite(ar);
                }
            }

            CheckCompletionBeforeNextReceive(message, asyncRequest);
        }
Example #22
0
        /// <summary>
        /// Generate SSPI context
        /// </summary>
        /// <param name="sspiClientContextStatus">SSPI client context status</param>
        /// <param name="receivedBuff">Receive buffer</param>
        /// <param name="sendBuff">Send buffer</param>
        /// <param name="serverName">Service Principal Name buffer</param>
        public void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[] serverName)
        {
            SafeDeleteContext   securityContext   = sspiClientContextStatus.SecurityContext;
            ContextFlagsPal     contextFlags      = sspiClientContextStatus.ContextFlags;
            SafeFreeCredentials credentialsHandle = sspiClientContextStatus.CredentialsHandle;

            string securityPackage = NegotiationInfoClass.Negotiate;

            if (securityContext == null)
            {
                credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(securityPackage, false);
            }

            int tokenSize = NegotiateStreamPal.QueryMaxTokenSize(securityPackage);

            byte[] resultToken = new byte[tokenSize];

            ContextFlagsPal requestedContextFlags = ContextFlagsPal.Connection
                                                    | ContextFlagsPal.Confidentiality
                                                    | ContextFlagsPal.Delegate
                                                    | ContextFlagsPal.MutualAuth;

            string serverSPN = System.Text.Encoding.UTF8.GetString(serverName);

            SecurityStatusPal statusCode = NegotiateStreamPal.InitializeSecurityContext(
                ref credentialsHandle,
                ref securityContext,
                serverSPN,
                requestedContextFlags,
                receivedBuff,
                null,
                ref resultToken,
                ref contextFlags);

            if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded ||
                statusCode.ErrorCode == SecurityStatusPalErrorCode.CompAndContinue)
            {
                statusCode  = NegotiateStreamPal.CompleteAuthToken(ref securityContext, resultToken);
                resultToken = null;
            }

            sendBuff = resultToken;
            if (sendBuff == null)
            {
                sendBuff = Array.Empty <byte>();
            }

            sspiClientContextStatus.SecurityContext   = securityContext;
            sspiClientContextStatus.ContextFlags      = contextFlags;
            sspiClientContextStatus.CredentialsHandle = credentialsHandle;

            if (IsErrorStatus(statusCode.ErrorCode))
            {
                // Could not access Kerberos Ticket.
                //
                // SecurityStatusPalErrorCode.InternalError only occurs in Unix and always comes with a GssApiException,
                // so we don't need to check for a GssApiException here.
                if (statusCode.ErrorCode == SecurityStatusPalErrorCode.InternalError)
                {
                    throw new InvalidOperationException(SQLMessage.KerberosTicketMissingError() + "\n" + statusCode);
                }
                else
                {
                    throw new InvalidOperationException(SQLMessage.SSPIGenerateError() + "\n" + statusCode);
                }
            }
        }
Example #23
0
 public static Exception GetException(SecurityStatusPal status)
 {
     int win32Code = (int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(status);
     return new Win32Exception(win32Code);
 }
Example #24
0
        private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            if (asyncRequest != null)
            {
                asyncRequest.SetNextRequest(buffer, offset, count, s_resumeAsyncWriteCallback);
            }

            // We loop to this method from the callback.
            // If the last chunk was just completed from async callback (count < 0), we complete user request.
            if (count >= 0)
            {
                byte[] outBuffer = null;
                if (_pinnableOutputBufferInUse == null)
                {
                    if (_pinnableOutputBuffer == null)
                    {
                        _pinnableOutputBuffer = s_PinnableWriteBufferCache.AllocateBuffer();
                    }

                    _pinnableOutputBufferInUse = buffer;
                    outBuffer = _pinnableOutputBuffer;
                    if (PinnableBufferCacheEventSource.Log.IsEnabled())
                    {
                        PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Trying Pinnable", this.GetHashCode(), count, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer));
                    }
                }
                else
                {
                    if (PinnableBufferCacheEventSource.Log.IsEnabled())
                    {
                        PinnableBufferCacheEventSource.Log.DebugMessage2("In System.Net._SslStream.StartWriting BufferInUse", this.GetHashCode(), count);
                    }
                }

                do
                {
                    if (count == 0 && !SslStreamPal.CanEncryptEmptyMessage)
                    {
                        // If it's an empty message and the PAL doesn't support that,
                        // we're done.
                        break;
                    }

                    // Request a write IO slot.
                    if (_sslState.CheckEnqueueWrite(asyncRequest))
                    {
                        // Operation is async and has been queued, return.
                        return;
                    }

                    int chunkBytes = Math.Min(count, _sslState.MaxDataSize);
                    int encryptedBytes;
                    SecurityStatusPal status = _sslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes);
                    if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
                    {
                        // Re-handshake status is not supported.
                        ProtocolToken message = new ProtocolToken(null, status);
                        throw new IOException(SR.net_io_encrypt, message.GetException());
                    }

                    if (PinnableBufferCacheEventSource.Log.IsEnabled())
                    {
                        PinnableBufferCacheEventSource.Log.DebugMessage3("In System.Net._SslStream.StartWriting Got Encrypted Buffer",
                                                                         this.GetHashCode(), encryptedBytes, PinnableBufferCacheEventSource.AddressOfByteArray(outBuffer));
                    }

                    if (asyncRequest != null)
                    {
                        // Prepare for the next request.
                        asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, s_resumeAsyncWriteCallback);
                        Task t = _sslState.InnerStream.WriteAsync(outBuffer, 0, encryptedBytes);
                        if (t.IsCompleted)
                        {
                            t.GetAwaiter().GetResult();
                        }
                        else
                        {
                            IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest);
                            if (!ar.CompletedSynchronously)
                            {
                                return;
                            }
                            TaskToApm.End(ar);
                        }
                    }
                    else
                    {
                        _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes);
                    }

                    offset += chunkBytes;
                    count  -= chunkBytes;

                    // Release write IO slot.
                    _sslState.FinishWrite();
                } while (count != 0);
            }

            if (asyncRequest != null)
            {
                asyncRequest.CompleteUser();
            }

            if (buffer == _pinnableOutputBufferInUse)
            {
                _pinnableOutputBufferInUse = null;
                if (PinnableBufferCacheEventSource.Log.IsEnabled())
                {
                    PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode());
                }
            }
        }
Example #25
0
 internal ProtocolToken(byte[] data, SecurityStatusPal errorCode)
 {
     Status = errorCode;
     Payload = data;
     Size = data != null ? data.Length : 0;
 }
Example #26
0
        private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer)
        {
            ProtocolToken message = new ProtocolToken(null, status);
            if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"***Processing an error Status = {message.Status}");

            if (message.Renegotiate)
            {
                _sslState.ReplyOnReAuthentication(extraBuffer);

                // Loop on read.
                return -1;
            }

            if (message.CloseConnection)
            {
                _sslState.FinishRead(null);
                if (asyncRequest != null)
                {
                    asyncRequest.CompleteUser((object)0);
                }

                return 0;
            }

            throw new IOException(SR.net_io_decrypt, message.GetException());
        }
Example #27
0
        // This will initiate renegotiation or PHA for Tls1.3
        private async Task RenegotiateAsync <TIOAdapter>(CancellationToken cancellationToken)
            where TIOAdapter : IReadWriteAdapter
        {
            if (Interlocked.Exchange(ref _nestedAuth, 1) == 1)
            {
                throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, "authenticate"));
            }

            if (Interlocked.Exchange(ref _nestedRead, 1) == 1)
            {
                throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, "read"));
            }

            if (Interlocked.Exchange(ref _nestedWrite, 1) == 1)
            {
                _nestedRead = 0;
                throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, "write"));
            }

            try
            {
                if (_buffer.ActiveLength > 0)
                {
                    throw new InvalidOperationException(SR.net_ssl_renegotiate_buffer);
                }

                _sslAuthenticationOptions !.RemoteCertRequired = true;
                _isRenego = true;


                SecurityStatusPal status = Renegotiate(out byte[]? nextmsg);

                if (nextmsg is { Length : > 0 })
                {
                    await TIOAdapter.WriteAsync(InnerStream, nextmsg, 0, nextmsg.Length, cancellationToken).ConfigureAwait(false);

                    await TIOAdapter.FlushAsync(InnerStream, cancellationToken).ConfigureAwait(false);
                }

                if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
                {
                    if (status.ErrorCode == SecurityStatusPalErrorCode.NoRenegotiation)
                    {
                        // Peer does not want to renegotiate. That should keep session usable.
                        return;
                    }

                    throw SslStreamPal.GetException(status);
                }

                _buffer.EnsureAvailableSpace(InitialHandshakeBufferSize);

                ProtocolToken message;
                do
                {
                    message = await ReceiveBlobAsync <TIOAdapter>(cancellationToken).ConfigureAwait(false);

                    if (message.Size > 0)
                    {
                        await TIOAdapter.WriteAsync(InnerStream, message.Payload !, 0, message.Size, cancellationToken).ConfigureAwait(false);

                        await TIOAdapter.FlushAsync(InnerStream, cancellationToken).ConfigureAwait(false);
                    }
                }while (message.Status.ErrorCode == SecurityStatusPalErrorCode.ContinueNeeded);

                CompleteHandshake(_sslAuthenticationOptions !);
            }
        private Task WriteSingleChunk <TWriteAdapter>(TWriteAdapter writeAdapter, ReadOnlyMemory <byte> buffer)
            where TWriteAdapter : struct, ISslWriteAdapter
        {
            // Request a write IO slot.
            Task ioSlot = writeAdapter.LockAsync();

            if (!ioSlot.IsCompletedSuccessfully)
            {
                // Operation is async and has been queued, return.
                return(WaitForWriteIOSlot(writeAdapter, ioSlot, buffer));
            }

            byte[] rentedBuffer = ArrayPool <byte> .Shared.Rent(buffer.Length + FrameOverhead);

            byte[] outBuffer = rentedBuffer;

            SecurityStatusPal status = _sslState.EncryptData(buffer, ref outBuffer, out int encryptedBytes);

            if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
            {
                // Re-handshake status is not supported.
                ArrayPool <byte> .Shared.Return(rentedBuffer);

                ProtocolToken message = new ProtocolToken(null, status);
                return(Task.FromException(new IOException(SR.net_io_encrypt, message.GetException())));
            }

            Task t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);

            if (t.IsCompletedSuccessfully)
            {
                ArrayPool <byte> .Shared.Return(rentedBuffer);

                _sslState.FinishWrite();
                return(t);
            }
            else
            {
                return(CompleteAsync(t, rentedBuffer));
            }

            async Task WaitForWriteIOSlot(TWriteAdapter wAdapter, Task lockTask, ReadOnlyMemory <byte> buff)
            {
                await lockTask.ConfigureAwait(false);

                await WriteSingleChunk(wAdapter, buff).ConfigureAwait(false);
            }

            async Task CompleteAsync(Task writeTask, byte[] bufferToReturn)
            {
                try
                {
                    await writeTask.ConfigureAwait(false);
                }
                finally
                {
                    ArrayPool <byte> .Shared.Return(bufferToReturn);

                    _sslState.FinishWrite();
                }
            }
        }
        public static Exception GetException(SecurityStatusPal status)
        {
            int win32Code = (int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(status);

            return(new Win32Exception(win32Code));
        }
        private async ValueTask <int> ReadAsyncInternal <TReadAdapter>(TReadAdapter adapter, Memory <byte> buffer)
            where TReadAdapter : ISslReadAdapter
        {
            if (Interlocked.Exchange(ref _nestedRead, 1) == 1)
            {
                throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, nameof(ReadAsync), "read"));
            }

            while (true)
            {
                int copyBytes;
                if (_decryptedBytesCount != 0)
                {
                    copyBytes = CopyDecryptedData(buffer);

                    _sslState.FinishRead(null);
                    _nestedRead = 0;

                    return(copyBytes);
                }

                copyBytes = await adapter.LockAsync(buffer).ConfigureAwait(false);

                try
                {
                    if (copyBytes > 0)
                    {
                        return(copyBytes);
                    }

                    ResetReadBuffer();
                    int readBytes = await FillBufferAsync(adapter, SecureChannel.ReadHeaderSize).ConfigureAwait(false);

                    if (readBytes == 0)
                    {
                        return(0);
                    }

                    int payloadBytes = _sslState.GetRemainingFrameSize(_internalBuffer, _internalOffset, readBytes);
                    if (payloadBytes < 0)
                    {
                        throw new IOException(SR.net_frame_read_size);
                    }

                    readBytes = await FillBufferAsync(adapter, SecureChannel.ReadHeaderSize + payloadBytes).ConfigureAwait(false);

                    if (readBytes < 0)
                    {
                        throw new IOException(SR.net_frame_read_size);
                    }

                    // At this point, readBytes contains the size of the header plus body.
                    // Set _decrytpedBytesOffset/Count to the current frame we have (including header)
                    // DecryptData will decrypt in-place and modify these to point to the actual decrypted data, which may be smaller.
                    _decryptedBytesOffset = _internalOffset;
                    _decryptedBytesCount  = readBytes;
                    SecurityStatusPal status = _sslState.DecryptData(_internalBuffer, ref _decryptedBytesOffset, ref _decryptedBytesCount);

                    // Treat the bytes we just decrypted as consumed
                    // Note, we won't do another buffer read until the decrypted bytes are processed
                    ConsumeBufferedBytes(readBytes);

                    if (status.ErrorCode != SecurityStatusPalErrorCode.OK)
                    {
                        byte[] extraBuffer = null;
                        if (_decryptedBytesCount != 0)
                        {
                            extraBuffer = new byte[_decryptedBytesCount];
                            Buffer.BlockCopy(_internalBuffer, _decryptedBytesOffset, extraBuffer, 0, _decryptedBytesCount);

                            _decryptedBytesCount = 0;
                        }

                        ProtocolToken message = new ProtocolToken(null, status);
                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Info(null, $"***Processing an error Status = {message.Status}");
                        }

                        if (message.Renegotiate)
                        {
                            if (!_sslState._sslAuthenticationOptions.AllowRenegotiation)
                            {
                                throw new IOException(SR.net_ssl_io_renego);
                            }

                            _sslState.ReplyOnReAuthentication(extraBuffer);

                            // Loop on read.
                            return(-1);
                        }

                        if (message.CloseConnection)
                        {
                            _sslState.FinishRead(null);
                            return(0);
                        }

                        throw new IOException(SR.net_io_decrypt, message.GetException());
                    }
                }
                catch (Exception e)
                {
                    _sslState.FinishRead(null);

                    if (e is IOException)
                    {
                        throw;
                    }

                    throw new IOException(SR.net_io_read, e);
                }
                finally
                {
                    _nestedRead = 0;
                }
            }
        }
Example #31
0
 internal static bool IsError(SecurityStatusPal status)
 {
     return ((int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory);
 }
Example #32
0
 internal ProtocolToken(byte[] data, SecurityStatusPal status)
 {
     Status = status;
     Payload = data;
     Size = data != null ? data.Length : 0;
 }
 internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode)
 {
     return new Win32Exception(NTE_FAIL, statusCode.ToString());
 }
 internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode)
 {
     return new Win32Exception(NTE_FAIL, (statusCode.Exception != null) ? statusCode.Exception.Message : statusCode.ErrorCode.ToString());
 }
Example #35
0
 public static Exception GetException(SecurityStatusPal status)
 {
     return(status.Exception ?? new Win32Exception((int)status.ErrorCode));
 }
Example #36
0
 internal static bool IsError(SecurityStatusPal status)
 {
     return((int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory);
 }
Example #37
0
 public static Exception GetException(SecurityStatusPal status)
 {
     return(status.Exception ?? new Interop.AndroidCrypto.SslException((int)status.ErrorCode));
 }
 internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode)
 {
     return(new Win32Exception((int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(statusCode)));
 }
 internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode)
 {
     return new Win32Exception((int)SecurityStatusAdapterPal.GetInteropFromSecurityStatusPal(statusCode));
 }
Example #40
0
        //
        // Only processing SEC_I_RENEGOTIATE.
        //
        private int ProcessReadErrorCode(SecurityStatusPal status, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer)
        {
            ProtocolToken message = new ProtocolToken(null, status);

            if (GlobalLog.IsEnabled)
            {
                GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::***Processing an error Status = " + message.Status.ToString());
            }

            if (message.Renegotiate)
            {
                _sslState.ReplyOnReAuthentication(extraBuffer);

                // Loop on read.
                return -1;
            }

            if (message.CloseConnection)
            {
                _sslState.FinishRead(null);
                if (asyncRequest != null)
                {
                    asyncRequest.CompleteUser((object)0);
                }

                return 0;
            }

            throw new IOException(SR.net_io_decrypt, message.GetException());
        }
Example #41
0
 internal static Win32Exception CreateExceptionFromError(SecurityStatusPal statusCode)
 {
     return(new Win32Exception(NTE_FAIL, (statusCode.Exception != null) ? statusCode.Exception.Message : statusCode.ErrorCode.ToString()));
 }
Example #42
0
        //
        // Only processing SEC_I_RENEGOTIATE.
        //
        private int ProcessReadErrorCode(SecurityStatusPal errorCode, byte[] buffer, int offset, int count, byte[] extraBuffer)
        {
            // ERROR - examine what kind
            ProtocolToken message = new ProtocolToken(null, errorCode);

            GlobalLog.Print("SecureChannel#" + Logging.HashString(this) + "::***Processing an error Status = " + message.Status.ToString());

            if (message.Renegotiate)
            {
                _SslState.ReplyOnReAuthentication(extraBuffer);

                // Loop on read.
                return -1;
            }

            if (message.CloseConnection)
            {
                _SslState.FinishRead(null);
                return 0;
            }

            throw new IOException(SR.net_io_decrypt, message.GetException());
        }