private void StartSendBlob(byte[] message, LazyAsyncResult lazyResult)
{
Exception exception = null;
if (message != s_emptyMessage)
{
message = GetOutgoingBlob(message, ref exception);
}
if (exception != null)
{
// Signal remote side on a failed attempt.
StartSendAuthResetSignal(lazyResult, message, exception);
return;
}
if (HandshakeComplete)
{
if (_context.IsServer && !CheckSpn())
{
exception = new AuthenticationException(SR.net_auth_bad_client_creds_or_target_mismatch);
int statusCode = ERROR_TRUST_FAILURE;
message = new byte[8]; //sizeof(long)
for (int i = message.Length - 1; i >= 0; --i)
{
message[i] = (byte)(statusCode & 0xFF);
statusCode = (int)((uint)statusCode >> 8);
}
StartSendAuthResetSignal(lazyResult, message, exception);
return;
}
if (PrivateImpersonationLevel < _expectedImpersonationLevel)
{
exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, _expectedImpersonationLevel.ToString(), PrivateImpersonationLevel.ToString()));
int statusCode = ERROR_TRUST_FAILURE;
message = new byte[8]; //sizeof(long)
for (int i = message.Length - 1; i >= 0; --i)
{
message[i] = (byte)(statusCode & 0xFF);
statusCode = (int)((uint)statusCode >> 8);
}
StartSendAuthResetSignal(lazyResult, message, exception);
return;
}
ProtectionLevel result = _context.IsConfidentialityFlag ? ProtectionLevel.EncryptAndSign : _context.IsIntegrityFlag ? ProtectionLevel.Sign : ProtectionLevel.None;
if (result < _expectedProtectionLevel)
{
exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, result.ToString(), _expectedProtectionLevel.ToString()));
int statusCode = ERROR_TRUST_FAILURE;
message = new byte[8]; //sizeof(long)
for (int i = message.Length - 1; i >= 0; --i)
{
message[i] = (byte)(statusCode & 0xFF);
statusCode = (int)((uint)statusCode >> 8);
}
StartSendAuthResetSignal(lazyResult, message, exception);
return;
}
// Signal remote party that we are done
_framer.WriteHeader.MessageId = FrameHeader.HandshakeDoneId;
if (_context.IsServer)
{
// Server may complete now because client SSPI would not complain at this point.
_remoteOk = true;
// However the client will wait for server to send this ACK
//Force signaling server OK to the client
if (message == null)
{
message = s_emptyMessage;
}
}
}
else if (message == null || message == s_emptyMessage)
{
throw new InternalException();
}
if (message != null)
{
//even if we are completed, there could be a blob for sending.
if (lazyResult == null)
{
_framer.WriteMessage(message);
}
else
{
IAsyncResult ar = _framer.BeginWriteMessage(message, s_writeCallback, lazyResult);
if (!ar.CompletedSynchronously)
{
return;
}
_framer.EndWriteMessage(ar);
}
}
CheckCompletionBeforeNextReceive(lazyResult);
}