// - Loads the channel parameters // - Optionally verifies the Remote Certificate // - Sets HandshakeCompleted flag // - Sets the guarding event if other thread is waiting for // handshake completion // // - Returns false if failed to verify the Remote Cert // private bool CompleteHandshake(ref ProtocolToken alertToken) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this); } _context.ProcessHandshakeSuccess(); if (!_context.VerifyRemoteCertificate(_sslAuthenticationOptions.CertValidationDelegate, ref alertToken)) { _handshakeCompleted = false; if (NetEventSource.IsEnabled) { NetEventSource.Exit(this, false); } return(false); } _handshakeCompleted = true; if (NetEventSource.IsEnabled) { NetEventSource.Exit(this, true); } return(true); }
// // 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()); }
// // 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); }
// // This will check and logically complete / fail the auth handshake. // private void CheckCompletionBeforeNextReceive(ProtocolToken message) { if (message.Failed) { SendAuthResetSignal(null, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_auth_SSPI, message.GetException()))); return; } else if (message.Done) { ProtocolToken alertToken = null; if (!CompleteHandshake(ref alertToken)) { SendAuthResetSignal(alertToken, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_validation, null))); return; } // Release waiting IO if any. Presumably it should not throw. // Otherwise application may get not expected type of the exception. FinishHandshake(null); return; } ReceiveBlob(message.Payload); }
internal void BeginShutdown(LazyAsyncResult lazyResult) { HandshakeProtocolRequest asyncRequest = new HandshakeProtocolRequest(lazyResult); if (Interlocked.Exchange(ref _NestedWrite, 1) == 1) { throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginShutdown" : "Shutdown"), "shutdown")); } bool failed = false; try { ProtocolToken message = _SslState.CreateShutdownMessage(); asyncRequest.SetNextRequest(HandshakeProtocolState.Shutdown, message, _ResumeHandshakeWriteCallback); StartHandshakeWrite(asyncRequest); } catch (Exception e) { _SslState.FinishWrite(); failed = true; throw; } finally { if (failed) { _NestedWrite = 0; } } }
private void CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) { if (message.Failed) { this.StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.GetString("net_auth_SSPI"), message.GetException())); } else if (message.Done && !this._PendingReHandshake) { if (this.CheckWin9xCachedSession()) { this._PendingReHandshake = true; this.Win9xSessionRestarted(); this.ForceAuthentication(false, null, asyncRequest); } else if (!this.CompleteHandshake()) { this.StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.GetString("net_ssl_io_cert_validation"), null)); } else { this.FinishHandshake(null, asyncRequest); } } else { this.StartReceiveBlob(message.Payload, asyncRequest); } }
internal void BeginRenegotiate(LazyAsyncResult lazyResult) { HandshakeProtocolRequest asyncRequest = new HandshakeProtocolRequest(lazyResult); if (Interlocked.Exchange(ref _NestedWrite, 1) == 1) { throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginRenegotiate" : "Renegotiate"), "renegotiate")); } bool failed = false; try { if (_SslState.IsServer) { ProtocolToken message = _SslState.CreateHelloRequestMessage(); asyncRequest.SetNextRequest(HandshakeProtocolState.SendHelloRequest, message, _ResumeHandshakeWriteCallback); } else { asyncRequest.SetNextRequest(HandshakeProtocolState.ClientRenegotiation, null, _ResumeHandshakeWriteCallback); } StartHandshakeWrite(asyncRequest); } catch (Exception e) { _SslState.FinishWrite(); failed = true; throw; } finally { if (failed) { _NestedWrite = 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()); }
private async ValueTask <ProtocolToken> ReceiveBlobAsync <TIOAdapter>(TIOAdapter adapter) where TIOAdapter : ISslIOAdapter { int readBytes = await FillHandshakeBufferAsync(adapter, SecureChannel.ReadHeaderSize).ConfigureAwait(false); if (readBytes == 0) { throw new IOException(SR.net_io_eof); } if (_framing == Framing.Unified || _framing == Framing.Unknown) { _framing = DetectFraming(_handshakeBuffer.ActiveReadOnlySpan); } int frameSize = GetFrameSize(_handshakeBuffer.ActiveReadOnlySpan); if (frameSize < 0) { throw new IOException(SR.net_frame_read_size); } if (_handshakeBuffer.ActiveLength < frameSize) { await FillHandshakeBufferAsync(adapter, frameSize).ConfigureAwait(false); } ProtocolToken token = _context.NextMessage(_handshakeBuffer.ActiveReadOnlySpan.Slice(0, frameSize)); _handshakeBuffer.Discard(frameSize); return(token); }
// // Only processing SEC_I_RENEGOTIATE. // private int ProcessReadErrorCode(Interop.SecurityStatus errorCode, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, 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); if (asyncRequest != null) { asyncRequest.CompleteUser((object)0); } return(0); } throw new IOException(SR.net_io_decrypt, message.GetException()); }
// private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, _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; do { // 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; SecurityStatus errorCode = _SslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (errorCode != SecurityStatus.OK) { // ProtocolToken message = new ProtocolToken(null, errorCode); throw new IOException(SR.GetString(SR.net_io_encrypt), message.GetException()); } if (asyncRequest != null) { // prepare for the next request asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, _ResumeAsyncWriteCallback); IAsyncResult ar = _SslState.InnerStream.BeginWrite(outBuffer, 0, encryptedBytes, _WriteCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } _SslState.InnerStream.EndWrite(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(); } }
internal async Task ForceAuthenticationAsync(bool receiveFirst, byte[] buffer, CancellationToken cancellationToken) { _framing = Framing.Unknown; ProtocolToken message; SslReadAsync adapter = new SslReadAsync(this, cancellationToken); if (!receiveFirst) { message = _context.NextMessage(buffer, 0, (buffer == null ? 0 : buffer.Length)); if (message.Failed) { // tracing done in NextMessage() throw new AuthenticationException(SR.net_auth_SSPI, message.GetException()); } await InnerStream.WriteAsync(message.Payload, cancellationToken).ConfigureAwait(false); } do { message = await ReceiveBlobAsync(adapter, buffer, cancellationToken).ConfigureAwait(false); if (message.Size > 0) { // If there is message send it out even if call failed. It may contain TLS Alert. await InnerStream.WriteAsync(message.Payload, cancellationToken).ConfigureAwait(false); } if (message.Failed) { throw new AuthenticationException(SR.net_auth_SSPI, message.GetException()); } } while (message.Status.ErrorCode != SecurityStatusPalErrorCode.OK); ProtocolToken alertToken = null; if (!CompleteHandshake(ref alertToken)) { SendAuthResetSignal(alertToken, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_validation, null))); } if (NetEventSource.IsEnabled) { NetEventSource.Log.SspiSelectedCipherSuite(nameof(ForceAuthenticationAsync), SslProtocol, CipherAlgorithm, CipherStrength, HashAlgorithm, HashStrength, KeyExchangeAlgorithm, KeyExchangeStrength); } }
// // This is to reset auth state on remote side. // If this write succeeds we will allow auth retrying. // private void SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception) { SetException(exception.SourceException); if (message == null || message.Size == 0) { // // We don't have an alert to send so cannot retry and fail prematurely. // exception.Throw(); } InnerStream.Write(message.Payload, 0, message.Size); exception.Throw(); }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, _ResumeAsyncWriteCallback); } if (count >= 0) { byte[] outBuffer = null; do { int num2; if (this._SslState.CheckEnqueueWrite(asyncRequest)) { return; } int num = Math.Min(count, this._SslState.MaxDataSize); SecurityStatus errorCode = this._SslState.EncryptData(buffer, offset, num, ref outBuffer, out num2); if (errorCode != SecurityStatus.OK) { ProtocolToken token = new ProtocolToken(null, errorCode); throw new IOException(SR.GetString("net_io_encrypt"), token.GetException()); } if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset + num, count - num, _ResumeAsyncWriteCallback); IAsyncResult asyncResult = this._SslState.InnerStream.BeginWrite(outBuffer, 0, num2, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } this._SslState.InnerStream.EndWrite(asyncResult); } else { this._SslState.InnerStream.Write(outBuffer, 0, num2); } offset += num; count -= num; this._SslState.FinishWrite(); }while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } }
// 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); }
private async ValueTask <ProtocolToken> ReceiveBlobAsync <TIOAdapter>(TIOAdapter adapter) where TIOAdapter : ISslIOAdapter { ResetReadBuffer(); int readBytes = await FillBufferAsync(adapter, SecureChannel.ReadHeaderSize).ConfigureAwait(false); if (readBytes == 0) { throw new IOException(SR.net_io_eof); } if (_framing == Framing.Unified || _framing == Framing.Unknown) { _framing = DetectFraming(_internalBuffer, readBytes); } int payloadBytes = GetRemainingFrameSize(_internalBuffer, _internalOffset, readBytes); if (payloadBytes < 0) { throw new IOException(SR.net_frame_read_size); } int frameSize = SecureChannel.ReadHeaderSize + payloadBytes; if (readBytes < frameSize) { readBytes = await FillBufferAsync(adapter, frameSize).ConfigureAwait(false); Debug.Assert(readBytes >= 0); if (readBytes == 0) { throw new IOException(SR.net_io_eof); } } ProtocolToken token = _context.NextMessage(_internalBuffer, _internalOffset, frameSize); ConsumeBufferedBytes(frameSize); return(token); }
private int ProcessReadErrorCode(SecurityStatus errorCode, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken token = new ProtocolToken(null, errorCode); if (token.Renegotiate) { this._SslState.ReplyOnReAuthentication(extraBuffer); return(-1); } if (!token.CloseConnection) { throw new IOException(SR.GetString("net_io_decrypt"), token.GetException()); } this._SslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser(0); } return(0); }
private void StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception) { if ((message == null) || (message.Size == 0)) { throw exception; } if (asyncRequest == null) { this.InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = exception; IAsyncResult asyncResult = this.InnerStream.BeginWrite(message.Payload, 0, message.Size, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } this.InnerStream.EndWrite(asyncResult); } throw exception; }
private void StartSendBlob(byte[] incoming, int count, AsyncProtocolRequest asyncRequest) { ProtocolToken message = this.Context.NextMessage(incoming, 0, count); this._SecurityStatus = message.Status; if (message.Size != 0) { if (this.Context.IsServer && (this._CachedSession == CachedSessionStatus.Unknown)) { this._CachedSession = (message.Size < 200) ? CachedSessionStatus.IsCached : CachedSessionStatus.IsNotCached; } if (this._Framing == Framing.Unified) { this._Framing = this.DetectFraming(message.Payload, message.Payload.Length); } if (((message.Done && this._ForceBufferingLastHandshakePayload) && ((this.InnerStream.GetType() == typeof(NetworkStream)) && !this._PendingReHandshake)) && !this.CheckWin9xCachedSession()) { this._LastPayload = message.Payload; } else if (asyncRequest == null) { this.InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = message; IAsyncResult asyncResult = this.InnerStream.BeginWrite(message.Payload, 0, message.Size, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } this.InnerStream.EndWrite(asyncResult); } } this.CheckCompletionBeforeNextReceive(message, asyncRequest); }
private void ProcessReceivedBlob(byte[] buffer, int count, AsyncProtocolRequest asyncRequest) { if (count == 0) { throw new AuthenticationException(SR.GetString("net_auth_eof"), null); } if (this._PendingReHandshake) { int offset = 0; SecurityStatus errorCode = this.PrivateDecryptData(buffer, ref offset, ref count); if (errorCode == SecurityStatus.OK) { Exception exception = this.EnqueueOldKeyDecryptedData(buffer, offset, count); if (exception != null) { this.StartSendAuthResetSignal(null, asyncRequest, exception); return; } this._Framing = Framing.None; this.StartReceiveBlob(buffer, asyncRequest); return; } if (errorCode != SecurityStatus.Renegotiate) { ProtocolToken token = new ProtocolToken(null, errorCode); this.StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.GetString("net_auth_SSPI"), token.GetException())); return; } this._PendingReHandshake = false; if (offset != 0) { Buffer.BlockCopy(buffer, offset, buffer, 0, count); } } this.StartSendBlob(buffer, count, asyncRequest); }
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()); } } }
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 { // 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); IAsyncResult ar = _sslState.InnerStreamAPM.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } _sslState.InnerStreamAPM.EndWrite(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()); } } }
public void SetNextRequest(HandshakeProtocolState state, ProtocolToken message, HandshakeProtocolCallback callback) { State = state; Message = message; SetNextRequest(null, 0, 0, (r) => callback((HandshakeProtocolRequest)r)); }
// - Loads the channel parameters // - Optionally verifies the Remote Certificate // - Sets HandshakeCompleted flag // - Sets the guarding event if other thread is waiting for // handshake completion // // - Returns false if failed to verify the Remote Cert // private bool CompleteHandshake(ref ProtocolToken alertToken) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); Context.ProcessHandshakeSuccess(); if (!Context.VerifyRemoteCertificate(_certValidationDelegate, ref alertToken)) { _handshakeCompleted = false; _certValidationFailed = true; if (NetEventSource.IsEnabled) NetEventSource.Exit(this, false); return false; } _certValidationFailed = false; _handshakeCompleted = true; if (NetEventSource.IsEnabled) NetEventSource.Exit(this, true); return true; }
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 { // 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; Interop.SecurityStatus errorCode = _SslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (errorCode != Interop.SecurityStatus.OK) { ProtocolToken message = new ProtocolToken(null, errorCode); 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); IAsyncResult ar = _SslState.InnerStreamAPM.BeginWrite(outBuffer, 0, encryptedBytes, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } _SslState.InnerStreamAPM.EndWrite(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()); } } }
/*++ VerifyRemoteCertificate - Validates the content of a Remote Certificate checkCRL if true, checks the certificate revocation list for validity. checkCertName, if true checks the CN field of the certificate --*/ //This method validates a remote certificate. //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build // A user callback has unique signature so it is safe to call it under permission assert. // internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback, ref ProtocolToken alertToken) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SecureChannel#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate"); } SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; // We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true. bool success = false; X509Chain chain = null; X509Certificate2 remoteCertificateEx = null; try { X509Certificate2Collection remoteCertificateStore; remoteCertificateEx = CertificateValidationPal.GetRemoteCertificate(_securityContext, out remoteCertificateStore); _isRemoteCertificateAvailable = remoteCertificateEx != null; if (remoteCertificateEx == null) { if (GlobalLog.IsEnabled) { GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!_remoteCertRequired).ToString()); } sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; } else { chain = new X509Chain(); chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; if (remoteCertificateStore != null) { chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore); } sslPolicyErrors |= CertificateValidationPal.VerifyCertificateProperties( chain, remoteCertificateEx, _checkCertName, _serverMode, _hostName); } if (remoteCertValidationCallback != null) { success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors); } else { if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired) { success = true; } else { success = (sslPolicyErrors == SslPolicyErrors.None); } } if (SecurityEventSource.Log.IsEnabled()) { LogCertificateValidation(remoteCertValidationCallback, sslPolicyErrors, success, chain); } if (GlobalLog.IsEnabled) { GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null ? "<null>" : remoteCertificateEx.ToString(true))); } if (!success) { alertToken = CreateFatalHandshakeAlertToken(sslPolicyErrors, chain); } } finally { // At least on Win2k server the chain is found to have dependencies on the original cert context. // So it should be closed first. if (chain != null) { chain.Dispose(); } if (remoteCertificateEx != null) { remoteCertificateEx.Dispose(); } } if (GlobalLog.IsEnabled) { GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::VerifyRemoteCertificate", success.ToString()); } return success; }
// // 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()); }
private void StartWriting(byte[] buffer, int offset, int count) { // 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 { // Request a write IO slot. if (_SslState.CheckEnqueueWrite(null)) { // Operation is async and has been queued, return. return; } int chunkBytes = Math.Min(count, _SslState.MaxDataSize); int encryptedBytes; SecurityStatusPal errorCode = _SslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (errorCode != SecurityStatusPal.OK) { ProtocolToken message = new ProtocolToken(null, errorCode); 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)); } _SslState.InnerStream.Write(outBuffer, 0, encryptedBytes); offset += chunkBytes; count -= chunkBytes; // Release write IO slot. _SslState.FinishWrite(); } while (count != 0); } if (buffer == _PinnableOutputBufferInUse) { _PinnableOutputBufferInUse = null; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage1("In System.Net._SslStream.StartWriting Freeing buffer.", this.GetHashCode()); } } }
public void SetNextRequest (HandshakeProtocolState state, ProtocolToken message, HandshakeProtocolCallback callback) { State = state; Message = message; SetNextRequest (null, 0, 0, (r) => callback ((HandshakeProtocolRequest)r)); }
// - Loads the channel parameters // - Optionally verifies the Remote Certificate // - Sets HandshakeCompleted flag // - Sets the guarding event if other thread is waiting for // handshake completion // // - Returns false if failed to verify the Remote Cert // private bool CompleteHandshake(ref ProtocolToken alertToken) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("CompleteHandshake"); } Context.ProcessHandshakeSuccess(); if (!Context.VerifyRemoteCertificate(_certValidationDelegate, ref alertToken)) { _handshakeCompleted = false; _certValidationFailed = true; if (GlobalLog.IsEnabled) { GlobalLog.Leave("CompleteHandshake", false); } return false; } _certValidationFailed = false; _handshakeCompleted = true; if (GlobalLog.IsEnabled) { GlobalLog.Leave("CompleteHandshake", true); } return true; }
// // // private void ProcessReceivedBlob(byte[] buffer, int count, AsyncProtocolRequest asyncRequest) { if (count == 0) { // EOF received throw new AuthenticationException(SR.GetString(SR.net_auth_eof), null); } if (_PendingReHandshake) { int offset = 0; SecurityStatus status = PrivateDecryptData(buffer, ref offset, ref count); if (status == SecurityStatus.OK) { Exception e = EnqueueOldKeyDecryptedData(buffer, offset, count); if (e != null) { StartSendAuthResetSignal(null, asyncRequest, e); return; } // Again, forget about framing we can get a new one at any time _Framing = Framing.None; StartReceiveBlob(buffer, asyncRequest); return; } else if (status != SecurityStatus.Renegotiate) { // fail re-handshake ProtocolToken message = new ProtocolToken(null, status); StartSendAuthResetSignal(null, asyncRequest, new AuthenticationException(SR.GetString(SR.net_auth_SSPI), message.GetException())); return; } // Got it, now we should expect only handshake messages _PendingReHandshake = false; if (offset != 0) { Buffer.BlockCopy(buffer, offset, buffer, 0, count); } } StartSendBlob(buffer, count, asyncRequest); }
private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload) { List<BufferOffsetSize> list = null; SecurityStatus oK = SecurityStatus.OK; foreach (BufferOffsetSize size in buffers) { int num2; int count = Math.Min(size.Size, this._SslState.MaxDataSize); byte[] outBuffer = null; oK = this._SslState.EncryptData(size.Buffer, size.Offset, count, ref outBuffer, out num2); if (oK != SecurityStatus.OK) { break; } if ((count != size.Size) || (list != null)) { if (list == null) { list = new List<BufferOffsetSize>(buffers.Length * ((size.Size / count) + 1)); if (lastHandshakePayload != null) { list.Add(new BufferOffsetSize(lastHandshakePayload, false)); } foreach (BufferOffsetSize size2 in buffers) { if (size2 == size) { break; } list.Add(size2); } } list.Add(new BufferOffsetSize(outBuffer, 0, num2, false)); while ((size.Size -= count) != 0) { size.Offset += count; count = Math.Min(size.Size, this._SslState.MaxDataSize); oK = this._SslState.EncryptData(size.Buffer, size.Offset, count, ref outBuffer, out num2); if (oK != SecurityStatus.OK) { break; } list.Add(new BufferOffsetSize(outBuffer, 0, num2, false)); } } else { size.Buffer = outBuffer; size.Offset = 0; size.Size = num2; } if (oK != SecurityStatus.OK) { break; } } if (oK != SecurityStatus.OK) { ProtocolToken token = new ProtocolToken(null, oK); throw new IOException(SR.GetString("net_io_encrypt"), token.GetException()); } if (list != null) { buffers = list.ToArray(); return buffers; } if (lastHandshakePayload != null) { BufferOffsetSize[] destinationArray = new BufferOffsetSize[buffers.Length + 1]; Array.Copy(buffers, 0, destinationArray, 1, buffers.Length); destinationArray[0] = new BufferOffsetSize(lastHandshakePayload, false); buffers = destinationArray; } return buffers; }
// // This will check and logically complete / fail the auth handshake. // private void CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) { if (message.Failed) { StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_auth_SSPI, message.GetException()))); return; } else if (message.Done && !_pendingReHandshake) { if (!CompleteHandshake()) { StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_validation, null))); return; } // Release waiting IO if any. Presumably it should not throw. // Otherwise application may get not expected type of the exception. FinishHandshake(null, asyncRequest); return; } StartReceiveBlob(message.Payload, asyncRequest); }
// // This is to reset auth state on remote side. // If this write succeeds we will allow auth retrying. // private void StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception) { if (message == null || message.Size == 0) { // // We don't have an alert to send so cannot retry and fail prematurely. // exception.Throw(); } if (asyncRequest == null) { InnerStream.Write(message.Payload, 0, message.Size); } else { asyncRequest.AsyncState = exception; IAsyncResult ar = InnerStreamAPM.BeginWrite(message.Payload, 0, message.Size, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } InnerStreamAPM.EndWrite(ar); } exception.Throw(); }
private ProtocolToken GenerateAlertToken() { byte[] nextmsg = null; SecurityStatusPal status; status = GenerateToken(null, 0, 0, ref nextmsg); ProtocolToken token = new ProtocolToken(nextmsg, status); return token; }
// internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); byte[] nextmsg = null; SecurityStatusPal status = GenerateToken(incoming, offset, count, ref nextmsg); if (!_serverMode && status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "NextMessage() returned SecurityStatusPal.CredentialsNeeded"); SetRefreshCredentialNeeded(); status = GenerateToken(incoming, offset, count, ref nextmsg); } ProtocolToken token = new ProtocolToken(nextmsg, status); if (NetEventSource.IsEnabled) NetEventSource.Exit(this, token); return token; }
private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload) { List <BufferOffsetSize> list = null; SecurityStatus oK = SecurityStatus.OK; foreach (BufferOffsetSize size in buffers) { int num2; int count = Math.Min(size.Size, this._SslState.MaxDataSize); byte[] outBuffer = null; oK = this._SslState.EncryptData(size.Buffer, size.Offset, count, ref outBuffer, out num2); if (oK != SecurityStatus.OK) { break; } if ((count != size.Size) || (list != null)) { if (list == null) { list = new List <BufferOffsetSize>(buffers.Length * ((size.Size / count) + 1)); if (lastHandshakePayload != null) { list.Add(new BufferOffsetSize(lastHandshakePayload, false)); } foreach (BufferOffsetSize size2 in buffers) { if (size2 == size) { break; } list.Add(size2); } } list.Add(new BufferOffsetSize(outBuffer, 0, num2, false)); while ((size.Size -= count) != 0) { size.Offset += count; count = Math.Min(size.Size, this._SslState.MaxDataSize); oK = this._SslState.EncryptData(size.Buffer, size.Offset, count, ref outBuffer, out num2); if (oK != SecurityStatus.OK) { break; } list.Add(new BufferOffsetSize(outBuffer, 0, num2, false)); } } else { size.Buffer = outBuffer; size.Offset = 0; size.Size = num2; } if (oK != SecurityStatus.OK) { break; } } if (oK != SecurityStatus.OK) { ProtocolToken token = new ProtocolToken(null, oK); throw new IOException(SR.GetString("net_io_encrypt"), token.GetException()); } if (list != null) { buffers = list.ToArray(); return(buffers); } if (lastHandshakePayload != null) { BufferOffsetSize[] destinationArray = new BufferOffsetSize[buffers.Length + 1]; Array.Copy(buffers, 0, destinationArray, 1, buffers.Length); destinationArray[0] = new BufferOffsetSize(lastHandshakePayload, false); buffers = destinationArray; } return(buffers); }
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()); }
// reAuthenticationData is only used on Windows in case of renegotiation. private async Task ForceAuthenticationAsync <TIOAdapter>(TIOAdapter adapter, bool receiveFirst, byte[] reAuthenticationData, bool isApm = false) where TIOAdapter : ISslIOAdapter { _framing = Framing.Unknown; ProtocolToken message; if (reAuthenticationData == null) { // prevent nesting only when authentication functions are called explicitly. e.g. handle renegotiation tansparently. if (Interlocked.Exchange(ref _nestedAuth, 1) == 1) { throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, isApm ? "BeginAuthenticate" : "Authenticate", "authenticate")); } } try { if (!receiveFirst) { message = _context.NextMessage(reAuthenticationData, 0, (reAuthenticationData == null ? 0 : reAuthenticationData.Length)); if (message.Size > 0) { await adapter.WriteAsync(message.Payload, 0, message.Size).ConfigureAwait(false); } if (message.Failed) { // tracing done in NextMessage() throw new AuthenticationException(SR.net_auth_SSPI, message.GetException()); } } do { message = await ReceiveBlobAsync(adapter).ConfigureAwait(false); if (message.Size > 0) { // If there is message send it out even if call failed. It may contain TLS Alert. await adapter.WriteAsync(message.Payload, 0, message.Size).ConfigureAwait(false); } if (message.Failed) { throw new AuthenticationException(SR.net_auth_SSPI, message.GetException()); } } while (message.Status.ErrorCode != SecurityStatusPalErrorCode.OK); ProtocolToken alertToken = null; if (!CompleteHandshake(ref alertToken)) { SendAuthResetSignal(alertToken, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_validation, null))); } } finally { if (reAuthenticationData == null) { _nestedAuth = 0; } } if (NetEventSource.IsEnabled) { NetEventSource.Log.SspiSelectedCipherSuite(nameof(ForceAuthenticationAsync), SslProtocol, CipherAlgorithm, CipherStrength, HashAlgorithm, HashStrength, KeyExchangeAlgorithm, KeyExchangeStrength); } }
private int ProcessReadErrorCode(SecurityStatus errorCode, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { ProtocolToken token = new ProtocolToken(null, errorCode); if (token.Renegotiate) { this._SslState.ReplyOnReAuthentication(extraBuffer); return -1; } if (!token.CloseConnection) { throw new IOException(SR.GetString("net_io_decrypt"), token.GetException()); } this._SslState.FinishRead(null); if (asyncRequest != null) { asyncRequest.CompleteUser(0); } return 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) { 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); byte[] rentedBuffer = ArrayPool <byte> .Shared.Rent(chunkBytes + FrameOverhead); byte[] outBuffer = rentedBuffer; int encryptedBytes = 0; 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); ArrayPool <byte> .Shared.Return(rentedBuffer); throw new IOException(SR.net_io_encrypt, message.GetException()); } 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) { ArrayPool <byte> .Shared.Return(rentedBuffer); t.GetAwaiter().GetResult(); } else { t = t.ContinueWith(s_freeWriteBufferCallback, rentedBuffer, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } TaskToApm.End(ar); } } else { try { _sslState.InnerStream.Write(outBuffer, 0, encryptedBytes); } finally { ArrayPool <byte> .Shared.Return(rentedBuffer); } } offset += chunkBytes; count -= chunkBytes; // Release write IO slot. _sslState.FinishWrite(); } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } }
// private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, _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; do { // 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; SecurityStatus errorCode = _SslState.EncryptData(buffer, offset, chunkBytes, ref outBuffer, out encryptedBytes); if (errorCode != SecurityStatus.OK) { // ProtocolToken message = new ProtocolToken(null, errorCode); throw new IOException(SR.GetString(SR.net_io_encrypt), message.GetException()); } if (asyncRequest != null) { // prepare for the next request asyncRequest.SetNextRequest(buffer, offset+chunkBytes, count-chunkBytes, _ResumeAsyncWriteCallback); IAsyncResult ar = _SslState.InnerStream.BeginWrite(outBuffer, 0, encryptedBytes, _WriteCallback, asyncRequest); if (!ar.CompletedSynchronously) { return; } _SslState.InnerStream.EndWrite(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(); } }
// // Performs encryption of an array of buffers, proceeds buffer by buffer, if the individual // buffer size exceeds a SSL limit of SecureChannel.MaxDataSize,the buffers are then split into smaller ones. // Returns the same array that is encrypted or a new array of encrypted buffers. // private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload) { List<BufferOffsetSize> arrayList = null; SecurityStatus status = SecurityStatus.OK; foreach(BufferOffsetSize buffer in buffers) { int chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize); byte[] outBuffer = null; int outSize; status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize); if (status != SecurityStatus.OK) break; if (chunkBytes != buffer.Size || arrayList != null) { if (arrayList == null) { arrayList = new List<BufferOffsetSize>(buffers.Length * (buffer.Size/chunkBytes+1)); if (lastHandshakePayload != null) arrayList.Add(new BufferOffsetSize(lastHandshakePayload, false)); foreach(BufferOffsetSize oldBuffer in buffers) { if (oldBuffer == buffer) break; arrayList.Add(oldBuffer); } } arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false)); while ((buffer.Size-=chunkBytes) != 0) { buffer.Offset += chunkBytes; chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize); outBuffer = null; status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize); if (status != SecurityStatus.OK) break; arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false)); } } else { buffer.Buffer = outBuffer; buffer.Offset = 0; buffer.Size = outSize; } if (status != SecurityStatus.OK) break; } if (status != SecurityStatus.OK) { // ProtocolToken message = new ProtocolToken(null, status); throw new IOException(SR.GetString(SR.net_io_encrypt), message.GetException()); } if (arrayList != null) buffers = arrayList.ToArray(); else if (lastHandshakePayload != null) { BufferOffsetSize[] result = new BufferOffsetSize[buffers.Length+1]; Array.Copy(buffers, 0, result, 1, buffers.Length); result[0] = new BufferOffsetSize(lastHandshakePayload, false); buffers = result; } return buffers; }
// // 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()); }
// // Codes we process (Anything else - fail) // // - SEC_I_RENEGOTIATE // private int ProcessReadErrorCode(SecurityStatus errorCode, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest, byte[] extraBuffer) { // ERROR - examine what kind ProtocolToken message = new ProtocolToken(null, errorCode); GlobalLog.Print("SecureChannel#" + ValidationHelper.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; } // Otherwise bail out. throw new IOException(SR.GetString(SR.net_io_decrypt), message.GetException()); }
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; } } }
private void ProcessReceivedBlob(byte[] buffer, int count, AsyncProtocolRequest asyncRequest) { if (count == 0) { // EOF received. throw new AuthenticationException(SR.net_auth_eof, null); } if (_pendingReHandshake) { int offset = 0; SecurityStatusPal status = PrivateDecryptData(buffer, ref offset, ref count); if (status.ErrorCode == SecurityStatusPalErrorCode.OK) { Exception e = EnqueueOldKeyDecryptedData(buffer, offset, count); if (e != null) { StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(e)); return; } _Framing = Framing.Unknown; StartReceiveBlob(buffer, asyncRequest); return; } else if (status.ErrorCode != SecurityStatusPalErrorCode.Renegotiate) { // Fail re-handshake. ProtocolToken message = new ProtocolToken(null, status); StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_auth_SSPI, message.GetException()))); return; } // We expect only handshake messages from now. _pendingReHandshake = false; if (offset != 0) { Buffer.BlockCopy(buffer, offset, buffer, 0, count); } } StartSendBlob(buffer, count, asyncRequest); }
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(); } } }
// // Performs encryption of an array of buffers, proceeds buffer by buffer, if the individual // buffer size exceeds a SSL limit of SecureChannel.MaxDataSize,the buffers are then split into smaller ones. // Returns the same array that is encrypted or a new array of encrypted buffers. // private BufferOffsetSize[] EncryptBuffers(BufferOffsetSize[] buffers, byte[] lastHandshakePayload) { List <BufferOffsetSize> arrayList = null; SecurityStatus status = SecurityStatus.OK; foreach (BufferOffsetSize buffer in buffers) { int chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize); byte[] outBuffer = null; int outSize; status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize); if (status != SecurityStatus.OK) { break; } if (chunkBytes != buffer.Size || arrayList != null) { if (arrayList == null) { arrayList = new List <BufferOffsetSize>(buffers.Length * (buffer.Size / chunkBytes + 1)); if (lastHandshakePayload != null) { arrayList.Add(new BufferOffsetSize(lastHandshakePayload, false)); } foreach (BufferOffsetSize oldBuffer in buffers) { if (oldBuffer == buffer) { break; } arrayList.Add(oldBuffer); } } arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false)); while ((buffer.Size -= chunkBytes) != 0) { buffer.Offset += chunkBytes; chunkBytes = Math.Min(buffer.Size, _SslState.MaxDataSize); outBuffer = null; status = _SslState.EncryptData(buffer.Buffer, buffer.Offset, chunkBytes, ref outBuffer, out outSize); if (status != SecurityStatus.OK) { break; } arrayList.Add(new BufferOffsetSize(outBuffer, 0, outSize, false)); } } else { buffer.Buffer = outBuffer; buffer.Offset = 0; buffer.Size = outSize; } if (status != SecurityStatus.OK) { break; } } if (status != SecurityStatus.OK) { // ProtocolToken message = new ProtocolToken(null, status); throw new IOException(SR.GetString(SR.net_io_encrypt), message.GetException()); } if (arrayList != null) { buffers = arrayList.ToArray(); } else if (lastHandshakePayload != null) { BufferOffsetSize[] result = new BufferOffsetSize[buffers.Length + 1]; Array.Copy(buffers, 0, result, 1, buffers.Length); result[0] = new BufferOffsetSize(lastHandshakePayload, false); buffers = result; } return(buffers); }
// internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) { GlobalLog.Enter("SecureChannel#" + ValidationHelper.HashString(this) + "::NextMessage"); byte[] nextmsg = null; SecurityStatus errorCode = GenerateToken(incoming, offset, count, ref nextmsg); if (!m_ServerMode && errorCode == SecurityStatus.CredentialsNeeded) { GlobalLog.Print("SecureChannel#" + ValidationHelper.HashString(this) + "::NextMessage() returned SecurityStatus.CredentialsNeeded"); SetRefreshCredentialNeeded(); errorCode = GenerateToken(incoming, offset, count, ref nextmsg); } ProtocolToken token = new ProtocolToken(nextmsg, errorCode); GlobalLog.Leave("SecureChannel#" + ValidationHelper.HashString(this) + "::NextMessage", token.ToString()); return token; }
// internal ProtocolToken NextMessage(byte[] incoming, int offset, int count) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("SecureChannel#" + LoggingHash.HashString(this) + "::NextMessage"); } byte[] nextmsg = null; SecurityStatusPal status = GenerateToken(incoming, offset, count, ref nextmsg); if (!_serverMode && status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded) { if (GlobalLog.IsEnabled) { GlobalLog.Print("SecureChannel#" + LoggingHash.HashString(this) + "::NextMessage() returned SecurityStatusPal.CredentialsNeeded"); } SetRefreshCredentialNeeded(); status = GenerateToken(incoming, offset, count, ref nextmsg); } ProtocolToken token = new ProtocolToken(nextmsg, status); if (GlobalLog.IsEnabled) { GlobalLog.Leave("SecureChannel#" + LoggingHash.HashString(this) + "::NextMessage", token.ToString()); } return token; }
private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) { if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset, count, _ResumeAsyncWriteCallback); } if (count >= 0) { byte[] outBuffer = null; do { int num2; if (this._SslState.CheckEnqueueWrite(asyncRequest)) { return; } int num = Math.Min(count, this._SslState.MaxDataSize); SecurityStatus errorCode = this._SslState.EncryptData(buffer, offset, num, ref outBuffer, out num2); if (errorCode != SecurityStatus.OK) { ProtocolToken token = new ProtocolToken(null, errorCode); throw new IOException(SR.GetString("net_io_encrypt"), token.GetException()); } if (asyncRequest != null) { asyncRequest.SetNextRequest(buffer, offset + num, count - num, _ResumeAsyncWriteCallback); IAsyncResult asyncResult = this._SslState.InnerStream.BeginWrite(outBuffer, 0, num2, _WriteCallback, asyncRequest); if (!asyncResult.CompletedSynchronously) { return; } this._SslState.InnerStream.EndWrite(asyncResult); } else { this._SslState.InnerStream.Write(outBuffer, 0, num2); } offset += num; count -= num; this._SslState.FinishWrite(); } while (count != 0); } if (asyncRequest != null) { asyncRequest.CompleteUser(); } }