{
private JavaProxy.RemoteCertificateValidationResult VerifyRemoteCertificate()
{
- ProtocolToken? alertToken = null;
+ ProtocolToken alertToken = default;
var isValid = VerifyRemoteCertificate(
_sslAuthenticationOptions.CertValidationDelegate,
_sslAuthenticationOptions.CertificateContext?.Trust,
};
}
- private bool TryGetRemoteCertificateValidationResult(out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus, out ProtocolToken? alertToken, out bool isValid)
+ private bool TryGetRemoteCertificateValidationResult(out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus, ref ProtocolToken alertToken, out bool isValid)
{
JavaProxy.RemoteCertificateValidationResult? validationResult = _securityContext?.SslStreamProxy.ValidationResult;
sslPolicyErrors = validationResult?.SslPolicyErrors ?? default;
chainStatus = validationResult?.ChainStatus ?? default;
isValid = validationResult?.IsValid ?? default;
- alertToken = validationResult?.AlertToken;
+ alertToken = validationResult?.AlertToken ?? default;
return validationResult is not null;
}
ProtocolToken message;
do
{
- message = await ReceiveBlobAsync<TIOAdapter>(cancellationToken).ConfigureAwait(false);
+ int frameSize = await ReceiveTlsFrameAsync<TIOAdapter>(cancellationToken).ConfigureAwait(false);
+ ProcessTlsFrame(frameSize, out message);
+
if (message.Size > 0)
{
await TIOAdapter.WriteAsync(InnerStream, new ReadOnlyMemory<byte>(message.Payload!, 0, message.Size), cancellationToken).ConfigureAwait(false);
private async Task ForceAuthenticationAsync<TIOAdapter>(bool receiveFirst, byte[]? reAuthenticationData, CancellationToken cancellationToken)
where TIOAdapter : IReadWriteAdapter
{
- ProtocolToken message;
+ ProtocolToken message = default;
bool handshakeCompleted = false;
if (reAuthenticationData == null)
throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, "authenticate"));
}
}
-
try
{
if (!receiveFirst)
{
- message = NextMessage(reAuthenticationData);
+ NextMessage(reAuthenticationData, out message);
+
if (message.Size > 0)
{
await TIOAdapter.WriteAsync(InnerStream, new ReadOnlyMemory<byte>(message.Payload!, 0, message.Size), cancellationToken).ConfigureAwait(false);
while (!handshakeCompleted)
{
- message = await ReceiveBlobAsync<TIOAdapter>(cancellationToken).ConfigureAwait(false);
+ int frameSize = await ReceiveTlsFrameAsync<TIOAdapter>(cancellationToken).ConfigureAwait(false);
+ ProcessTlsFrame(frameSize, out message);
ReadOnlyMemory<byte> payload = default;
if (message.Size > 0)
}
- private async ValueTask<ProtocolToken> ReceiveBlobAsync<TIOAdapter>(CancellationToken cancellationToken)
+ // This method will make sure we have at least one full TLS frame buffered.
+ private async ValueTask<int> ReceiveTlsFrameAsync<TIOAdapter>(CancellationToken cancellationToken)
where TIOAdapter : IReadWriteAdapter
{
int frameSize = await EnsureFullTlsFrameAsync<TIOAdapter>(cancellationToken).ConfigureAwait(false);
}
- return ProcessBlob(frameSize);
+ return frameSize;
}
// Calls crypto on received data. No IO inside.
- private ProtocolToken ProcessBlob(int frameSize)
+ private void ProcessTlsFrame(int frameSize, out ProtocolToken message)
{
int chunkSize = frameSize;
_buffer.DiscardEncrypted(frameSize);
}
- return NextMessage(availableData.Slice(0, chunkSize));
+ NextMessage(availableData.Slice(0, chunkSize), out message);
}
//
// 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)
+ private void SendAuthResetSignal(ReadOnlySpan<byte> alert, ExceptionDispatchInfo exception)
{
SetException(exception.SourceException);
- if (message == null || message.Size == 0)
+ if (alert.Length == 0)
{
//
// We don't have an alert to send so cannot retry and fail prematurely.
exception.Throw();
}
- InnerStream.Write(message.Payload!, 0, message.Size);
+ InnerStream.Write(alert);
exception.Throw();
}
//
// - Returns false if failed to verify the Remote Cert
//
- private bool CompleteHandshake(ref ProtocolToken? alertToken, out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus)
+ private bool CompleteHandshake(ref ProtocolToken alertToken, out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus)
{
ProcessHandshakeSuccess();
// The Java TrustManager callback is called only when the peer has a certificate. It's possible that
// the peer didn't provide any certificate (for example when the peer is the client) and the validation
// result hasn't been set. In that case we still need to run the verification at this point.
- if (TryGetRemoteCertificateValidationResult(out sslPolicyErrors, out chainStatus, out alertToken, out bool isValid))
+ if (TryGetRemoteCertificateValidationResult(out sslPolicyErrors, out chainStatus, ref alertToken, out bool isValid))
{
_handshakeCompleted = isValid;
return isValid;
private void CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
{
- ProtocolToken? alertToken = null;
+ ProtocolToken alertToken = default;
if (!CompleteHandshake(ref alertToken, out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus))
{
if (sslAuthenticationOptions!.CertValidationDelegate != null)
{
// there may be some chain errors but the decision was made by custom callback. Details should be tracing if enabled.
- SendAuthResetSignal(alertToken, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_custom_validation, null)));
+ SendAuthResetSignal(new ReadOnlySpan<byte>(alertToken.Payload), ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_ssl_io_cert_custom_validation, null)));
}
else if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors && chainStatus != X509ChainStatusFlags.NoError)
{
// We failed only because of chain and we have some insight.
- SendAuthResetSignal(alertToken, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.Format(SR.net_ssl_io_cert_chain_validation, chainStatus), null)));
+ SendAuthResetSignal(new ReadOnlySpan<byte>(alertToken.Payload), ExceptionDispatchInfo.Capture(new AuthenticationException(SR.Format(SR.net_ssl_io_cert_chain_validation, chainStatus), null)));
}
else
{
// Simple add sslPolicyErrors as crude info.
- SendAuthResetSignal(alertToken, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.Format(SR.net_ssl_io_cert_validation, sslPolicyErrors), null)));
+ SendAuthResetSignal(new ReadOnlySpan<byte>(alertToken.Payload), ExceptionDispatchInfo.Capture(new AuthenticationException(SR.Format(SR.net_ssl_io_cert_validation, sslPolicyErrors), null)));
}
}
}
}
//
- internal ProtocolToken NextMessage(ReadOnlySpan<byte> incomingBuffer)
+ internal void NextMessage(ReadOnlySpan<byte> incomingBuffer, out ProtocolToken token)
{
byte[]? nextmsg = null;
- SecurityStatusPal status = GenerateToken(incomingBuffer, ref nextmsg);
- ProtocolToken token = new ProtocolToken(nextmsg, status);
+ token.Status = GenerateToken(incomingBuffer, ref nextmsg);
+ token.Size = nextmsg?.Length ?? 0;
+ token.Payload = nextmsg;
if (NetEventSource.Log.IsEnabled())
{
if (token.Failed)
{
- NetEventSource.Error(this, $"Authentication failed. Status: {status}, Exception message: {token.GetException()!.Message}");
+ NetEventSource.Error(this, $"Authentication failed. Status: {token.Status}, Exception message: {token.GetException()!.Message}");
}
}
- return token;
}
/*++
--*/
//This method validates a remote certificate.
- internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remoteCertValidationCallback, SslCertificateTrust? trust, ref ProtocolToken? alertToken, out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus)
+ internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remoteCertValidationCallback, SslCertificateTrust? trust, ref ProtocolToken alertToken, out SslPolicyErrors sslPolicyErrors, out X509ChainStatusFlags chainStatus)
{
sslPolicyErrors = SslPolicyErrors.None;
chainStatus = X509ChainStatusFlags.NoError;
if (!success)
{
- alertToken = CreateFatalHandshakeAlertToken(sslPolicyErrors, chain!);
+ CreateFatalHandshakeAlertToken(sslPolicyErrors, chain!, ref alertToken);
if (chain != null)
{
foreach (X509ChainStatus status in chain.ChainStatus)
return success;
}
- private ProtocolToken? CreateFatalHandshakeAlertToken(SslPolicyErrors sslPolicyErrors, X509Chain chain)
+ private void CreateFatalHandshakeAlertToken(SslPolicyErrors sslPolicyErrors, X509Chain chain, ref ProtocolToken alertToken)
{
TlsAlertMessage alertMessage;
{
ExceptionDispatchInfo.Throw(status.Exception);
}
-
- return null;
}
- return GenerateAlertToken();
+ GenerateAlertToken(ref alertToken);
}
- private ProtocolToken? CreateShutdownToken()
+ private byte[]? CreateShutdownToken()
{
+ byte[]? nextmsg = null;
SecurityStatusPal status;
status = SslStreamPal.ApplyShutdownToken(_securityContext!);
return null;
}
- return GenerateAlertToken();
+ GenerateToken(default, ref nextmsg);
+
+ return nextmsg;
}
- private ProtocolToken GenerateAlertToken()
+ private void GenerateAlertToken(ref ProtocolToken alertToken)
{
byte[]? nextmsg = null;
SecurityStatusPal status;
status = GenerateToken(default, ref nextmsg);
- return new ProtocolToken(nextmsg, status);
+ alertToken.Payload = nextmsg;
+ alertToken.Size = nextmsg?.Length ?? 0;
+ alertToken.Status = status;
}
private static TlsAlertMessage GetAlertMessageFromChain(X509Chain chain)
}
// ProtocolToken - used to process and handle the return codes from the SSPI wrapper
- internal sealed class ProtocolToken
+ internal struct ProtocolToken
{
internal SecurityStatusPal Status;
internal byte[]? Payload;