1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 using System.IO; 7 using System.Security; 8 using System.Security.Principal; 9 using System.Threading; 10 using System.ComponentModel; 11 using System.Runtime.ExceptionServices; 12 using System.Security.Authentication; 13 using System.Security.Authentication.ExtendedProtection; 14 15 namespace System.Net.Security 16 { 17 // 18 // The class maintains the state of the authentication process and the security context. 19 // It encapsulates security context and does the real work in authentication and 20 // user data encryption 21 // 22 internal class NegoState 23 { 24 private static readonly byte[] s_emptyMessage = new byte[0]; // used in reference comparisons 25 private static readonly AsyncCallback s_readCallback = new AsyncCallback(ReadCallback); 26 private static readonly AsyncCallback s_writeCallback = new AsyncCallback(WriteCallback); 27 28 private Stream _innerStream; 29 private bool _leaveStreamOpen; 30 31 private Exception _exception; 32 33 private StreamFramer _framer; 34 private NTAuthentication _context; 35 36 private int _nestedAuth; 37 38 internal const int ERROR_TRUST_FAILURE = 1790; // Used to serialize protectionLevel or impersonationLevel mismatch error to the remote side. 39 internal const int MaxReadFrameSize = 64 * 1024; 40 internal const int MaxWriteDataSize = 63 * 1024; // 1k for the framing and trailer that is always less as per SSPI. 41 42 private bool _canRetryAuthentication; 43 private ProtectionLevel _expectedProtectionLevel; 44 private TokenImpersonationLevel _expectedImpersonationLevel; 45 private uint _writeSequenceNumber; 46 private uint _readSequenceNumber; 47 48 private ExtendedProtectionPolicy _extendedProtectionPolicy; 49 50 // SSPI does not send a server ack on successful auth. 51 // This is a state variable used to gracefully handle auth confirmation. 52 private bool _remoteOk = false; 53 NegoState(Stream innerStream, bool leaveStreamOpen)54 internal NegoState(Stream innerStream, bool leaveStreamOpen) 55 { 56 if (innerStream == null) 57 { 58 throw new ArgumentNullException("stream"); 59 } 60 61 _innerStream = innerStream; 62 _leaveStreamOpen = leaveStreamOpen; 63 } 64 65 internal static string DefaultPackage 66 { 67 get 68 { 69 return NegotiationInfoClass.Negotiate; 70 } 71 } 72 GetIdentity()73 internal IIdentity GetIdentity() 74 { 75 CheckThrow(true); 76 return NegotiateStreamPal.GetIdentity(_context); 77 } 78 ValidateCreateContext( string package, NetworkCredential credential, string servicePrincipalName, ExtendedProtectionPolicy policy, ProtectionLevel protectionLevel, TokenImpersonationLevel impersonationLevel)79 internal void ValidateCreateContext( 80 string package, 81 NetworkCredential credential, 82 string servicePrincipalName, 83 ExtendedProtectionPolicy policy, 84 ProtectionLevel protectionLevel, 85 TokenImpersonationLevel impersonationLevel) 86 { 87 if (policy != null) 88 { 89 // One of these must be set if EP is turned on 90 if (policy.CustomChannelBinding == null && policy.CustomServiceNames == null) 91 { 92 throw new ArgumentException(SR.net_auth_must_specify_extended_protection_scheme, nameof(policy)); 93 } 94 95 _extendedProtectionPolicy = policy; 96 } 97 else 98 { 99 _extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); 100 } 101 102 ValidateCreateContext(package, true, credential, servicePrincipalName, _extendedProtectionPolicy.CustomChannelBinding, protectionLevel, impersonationLevel); 103 } 104 ValidateCreateContext( string package, bool isServer, NetworkCredential credential, string servicePrincipalName, ChannelBinding channelBinding, ProtectionLevel protectionLevel, TokenImpersonationLevel impersonationLevel)105 internal void ValidateCreateContext( 106 string package, 107 bool isServer, 108 NetworkCredential credential, 109 string servicePrincipalName, 110 ChannelBinding channelBinding, 111 ProtectionLevel protectionLevel, 112 TokenImpersonationLevel impersonationLevel) 113 { 114 if (_exception != null && !_canRetryAuthentication) 115 { 116 ExceptionDispatchInfo.Throw(_exception); 117 } 118 119 if (_context != null && _context.IsValidContext) 120 { 121 throw new InvalidOperationException(SR.net_auth_reauth); 122 } 123 124 if (credential == null) 125 { 126 throw new ArgumentNullException(nameof(credential)); 127 } 128 129 if (servicePrincipalName == null) 130 { 131 throw new ArgumentNullException(nameof(servicePrincipalName)); 132 } 133 134 NegotiateStreamPal.ValidateImpersonationLevel(impersonationLevel); 135 if (_context != null && IsServer != isServer) 136 { 137 throw new InvalidOperationException(SR.net_auth_client_server); 138 } 139 140 _exception = null; 141 _remoteOk = false; 142 _framer = new StreamFramer(_innerStream); 143 _framer.WriteHeader.MessageId = FrameHeader.HandshakeId; 144 145 _expectedProtectionLevel = protectionLevel; 146 _expectedImpersonationLevel = isServer ? impersonationLevel : TokenImpersonationLevel.None; 147 _writeSequenceNumber = 0; 148 _readSequenceNumber = 0; 149 150 ContextFlagsPal flags = ContextFlagsPal.Connection; 151 152 // A workaround for the client when talking to Win9x on the server side. 153 if (protectionLevel == ProtectionLevel.None && !isServer) 154 { 155 package = NegotiationInfoClass.NTLM; 156 } 157 else if (protectionLevel == ProtectionLevel.EncryptAndSign) 158 { 159 flags |= ContextFlagsPal.Confidentiality; 160 } 161 else if (protectionLevel == ProtectionLevel.Sign) 162 { 163 // Assuming user expects NT4 SP4 and above. 164 flags |= (ContextFlagsPal.ReplayDetect | ContextFlagsPal.SequenceDetect | ContextFlagsPal.InitIntegrity); 165 } 166 167 if (isServer) 168 { 169 if (_extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.WhenSupported) 170 { 171 flags |= ContextFlagsPal.AllowMissingBindings; 172 } 173 174 if (_extendedProtectionPolicy.PolicyEnforcement != PolicyEnforcement.Never && 175 _extendedProtectionPolicy.ProtectionScenario == ProtectionScenario.TrustedProxy) 176 { 177 flags |= ContextFlagsPal.ProxyBindings; 178 } 179 } 180 else 181 { 182 // Server side should not request any of these flags. 183 if (protectionLevel != ProtectionLevel.None) 184 { 185 flags |= ContextFlagsPal.MutualAuth; 186 } 187 188 if (impersonationLevel == TokenImpersonationLevel.Identification) 189 { 190 flags |= ContextFlagsPal.InitIdentify; 191 } 192 193 if (impersonationLevel == TokenImpersonationLevel.Delegation) 194 { 195 flags |= ContextFlagsPal.Delegate; 196 } 197 } 198 199 _canRetryAuthentication = false; 200 201 try 202 { 203 _context = new NTAuthentication(isServer, package, credential, servicePrincipalName, flags, channelBinding); 204 } 205 catch (Win32Exception e) 206 { 207 throw new AuthenticationException(SR.net_auth_SSPI, e); 208 } 209 } 210 SetException(Exception e)211 private Exception SetException(Exception e) 212 { 213 if (_exception == null || !(_exception is ObjectDisposedException)) 214 { 215 _exception = e; 216 } 217 218 if (_exception != null && _context != null) 219 { 220 _context.CloseContext(); 221 } 222 223 return _exception; 224 } 225 226 internal bool IsAuthenticated 227 { 228 get 229 { 230 return _context != null && HandshakeComplete && _exception == null && _remoteOk; 231 } 232 } 233 234 internal bool IsMutuallyAuthenticated 235 { 236 get 237 { 238 if (!IsAuthenticated) 239 { 240 return false; 241 } 242 243 // Suppressing for NTLM since SSPI does not return correct value in the context flags. 244 if (_context.IsNTLM) 245 { 246 return false; 247 } 248 249 return _context.IsMutualAuthFlag; 250 } 251 } 252 253 internal bool IsEncrypted 254 { 255 get 256 { 257 return IsAuthenticated && _context.IsConfidentialityFlag; 258 } 259 } 260 261 internal bool IsSigned 262 { 263 get 264 { 265 return IsAuthenticated && (_context.IsIntegrityFlag || _context.IsConfidentialityFlag); 266 } 267 } 268 269 internal bool IsServer 270 { 271 get 272 { 273 return _context != null && _context.IsServer; 274 } 275 } 276 277 internal bool CanGetSecureStream 278 { 279 get 280 { 281 return (_context.IsConfidentialityFlag || _context.IsIntegrityFlag); 282 } 283 } 284 285 internal TokenImpersonationLevel AllowedImpersonation 286 { 287 get 288 { 289 CheckThrow(true); 290 return PrivateImpersonationLevel; 291 } 292 } 293 294 private TokenImpersonationLevel PrivateImpersonationLevel 295 { 296 get 297 { 298 // We should suppress the delegate flag in NTLM case. 299 return (_context.IsDelegationFlag && _context.ProtocolName != NegotiationInfoClass.NTLM) ? TokenImpersonationLevel.Delegation 300 : _context.IsIdentifyFlag ? TokenImpersonationLevel.Identification 301 : TokenImpersonationLevel.Impersonation; 302 } 303 } 304 305 private bool HandshakeComplete 306 { 307 get 308 { 309 return _context.IsCompleted && _context.IsValidContext; 310 } 311 } 312 CheckThrow(bool authSucessCheck)313 internal void CheckThrow(bool authSucessCheck) 314 { 315 if (_exception != null) 316 { 317 ExceptionDispatchInfo.Throw(_exception); 318 } 319 320 if (authSucessCheck && !IsAuthenticated) 321 { 322 throw new InvalidOperationException(SR.net_auth_noauth); 323 } 324 } 325 326 // 327 // This is to not depend on GC&SafeHandle class if the context is not needed anymore. 328 // Close()329 internal void Close() 330 { 331 // Mark this instance as disposed. 332 _exception = new ObjectDisposedException("NegotiateStream"); 333 if (_context != null) 334 { 335 _context.CloseContext(); 336 } 337 } 338 ProcessAuthentication(LazyAsyncResult lazyResult)339 internal void ProcessAuthentication(LazyAsyncResult lazyResult) 340 { 341 CheckThrow(false); 342 if (Interlocked.Exchange(ref _nestedAuth, 1) == 1) 343 { 344 throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, lazyResult == null ? "BeginAuthenticate" : "Authenticate", "authenticate")); 345 } 346 347 try 348 { 349 if (_context.IsServer) 350 { 351 // Listen for a client blob. 352 StartReceiveBlob(lazyResult); 353 } 354 else 355 { 356 // Start with the first blob. 357 StartSendBlob(null, lazyResult); 358 } 359 } 360 catch (Exception e) 361 { 362 // Round-trip it through SetException(). 363 e = SetException(e); 364 throw; 365 } 366 finally 367 { 368 if (lazyResult == null || _exception != null) 369 { 370 _nestedAuth = 0; 371 } 372 } 373 } 374 EndProcessAuthentication(IAsyncResult result)375 internal void EndProcessAuthentication(IAsyncResult result) 376 { 377 if (result == null) 378 { 379 throw new ArgumentNullException("asyncResult"); 380 } 381 382 LazyAsyncResult lazyResult = result as LazyAsyncResult; 383 if (lazyResult == null) 384 { 385 throw new ArgumentException(SR.Format(SR.net_io_async_result, result.GetType().FullName), "asyncResult"); 386 } 387 388 if (Interlocked.Exchange(ref _nestedAuth, 0) == 0) 389 { 390 throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndAuthenticate")); 391 } 392 393 // No "artificial" timeouts implemented so far, InnerStream controls that. 394 lazyResult.InternalWaitForCompletion(); 395 396 Exception e = lazyResult.Result as Exception; 397 398 if (e != null) 399 { 400 // Round-trip it through the SetException(). 401 e = SetException(e); 402 ExceptionDispatchInfo.Throw(e); 403 } 404 } 405 CheckSpn()406 private bool CheckSpn() 407 { 408 if (_context.IsKerberos) 409 { 410 return true; 411 } 412 413 if (_extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.Never || 414 _extendedProtectionPolicy.CustomServiceNames == null) 415 { 416 return true; 417 } 418 419 string clientSpn = _context.ClientSpecifiedSpn; 420 421 if (String.IsNullOrEmpty(clientSpn)) 422 { 423 if (_extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.WhenSupported) 424 { 425 return true; 426 } 427 } 428 else 429 { 430 return _extendedProtectionPolicy.CustomServiceNames.Contains(clientSpn); 431 } 432 433 return false; 434 } 435 436 // 437 // Client side starts here, but server also loops through this method. 438 // StartSendBlob(byte[] message, LazyAsyncResult lazyResult)439 private void StartSendBlob(byte[] message, LazyAsyncResult lazyResult) 440 { 441 Exception exception = null; 442 if (message != s_emptyMessage) 443 { 444 message = GetOutgoingBlob(message, ref exception); 445 } 446 447 if (exception != null) 448 { 449 // Signal remote side on a failed attempt. 450 StartSendAuthResetSignal(lazyResult, message, exception); 451 return; 452 } 453 454 if (HandshakeComplete) 455 { 456 if (_context.IsServer && !CheckSpn()) 457 { 458 exception = new AuthenticationException(SR.net_auth_bad_client_creds_or_target_mismatch); 459 int statusCode = ERROR_TRUST_FAILURE; 460 message = new byte[8]; //sizeof(long) 461 462 for (int i = message.Length - 1; i >= 0; --i) 463 { 464 message[i] = (byte)(statusCode & 0xFF); 465 statusCode = (int)((uint)statusCode >> 8); 466 } 467 468 StartSendAuthResetSignal(lazyResult, message, exception); 469 return; 470 } 471 472 if (PrivateImpersonationLevel < _expectedImpersonationLevel) 473 { 474 exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, _expectedImpersonationLevel.ToString(), PrivateImpersonationLevel.ToString())); 475 int statusCode = ERROR_TRUST_FAILURE; 476 message = new byte[8]; //sizeof(long) 477 478 for (int i = message.Length - 1; i >= 0; --i) 479 { 480 message[i] = (byte)(statusCode & 0xFF); 481 statusCode = (int)((uint)statusCode >> 8); 482 } 483 484 StartSendAuthResetSignal(lazyResult, message, exception); 485 return; 486 } 487 488 ProtectionLevel result = _context.IsConfidentialityFlag ? ProtectionLevel.EncryptAndSign : _context.IsIntegrityFlag ? ProtectionLevel.Sign : ProtectionLevel.None; 489 490 if (result < _expectedProtectionLevel) 491 { 492 exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, result.ToString(), _expectedProtectionLevel.ToString())); 493 int statusCode = ERROR_TRUST_FAILURE; 494 message = new byte[8]; //sizeof(long) 495 496 for (int i = message.Length - 1; i >= 0; --i) 497 { 498 message[i] = (byte)(statusCode & 0xFF); 499 statusCode = (int)((uint)statusCode >> 8); 500 } 501 502 StartSendAuthResetSignal(lazyResult, message, exception); 503 return; 504 } 505 506 // Signal remote party that we are done 507 _framer.WriteHeader.MessageId = FrameHeader.HandshakeDoneId; 508 if (_context.IsServer) 509 { 510 // Server may complete now because client SSPI would not complain at this point. 511 _remoteOk = true; 512 513 // However the client will wait for server to send this ACK 514 //Force signaling server OK to the client 515 if (message == null) 516 { 517 message = s_emptyMessage; 518 } 519 } 520 } 521 else if (message == null || message == s_emptyMessage) 522 { 523 throw new InternalException(); 524 } 525 526 if (message != null) 527 { 528 //even if we are completed, there could be a blob for sending. 529 if (lazyResult == null) 530 { 531 _framer.WriteMessage(message); 532 } 533 else 534 { 535 IAsyncResult ar = _framer.BeginWriteMessage(message, s_writeCallback, lazyResult); 536 if (!ar.CompletedSynchronously) 537 { 538 return; 539 } 540 _framer.EndWriteMessage(ar); 541 } 542 } 543 CheckCompletionBeforeNextReceive(lazyResult); 544 } 545 546 // 547 // This will check and logically complete the auth handshake. 548 // CheckCompletionBeforeNextReceive(LazyAsyncResult lazyResult)549 private void CheckCompletionBeforeNextReceive(LazyAsyncResult lazyResult) 550 { 551 if (HandshakeComplete && _remoteOk) 552 { 553 // We are done with success. 554 if (lazyResult != null) 555 { 556 lazyResult.InvokeCallback(); 557 } 558 559 return; 560 } 561 562 StartReceiveBlob(lazyResult); 563 } 564 565 // 566 // Server side starts here, but client also loops through this method. 567 // StartReceiveBlob(LazyAsyncResult lazyResult)568 private void StartReceiveBlob(LazyAsyncResult lazyResult) 569 { 570 byte[] message; 571 if (lazyResult == null) 572 { 573 message = _framer.ReadMessage(); 574 } 575 else 576 { 577 IAsyncResult ar = _framer.BeginReadMessage(s_readCallback, lazyResult); 578 if (!ar.CompletedSynchronously) 579 { 580 return; 581 } 582 583 message = _framer.EndReadMessage(ar); 584 } 585 586 ProcessReceivedBlob(message, lazyResult); 587 } 588 ProcessReceivedBlob(byte[] message, LazyAsyncResult lazyResult)589 private void ProcessReceivedBlob(byte[] message, LazyAsyncResult lazyResult) 590 { 591 // This is an EOF otherwise we would get at least *empty* message but not a null one. 592 if (message == null) 593 { 594 throw new AuthenticationException(SR.net_auth_eof, null); 595 } 596 597 // Process Header information. 598 if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeErrId) 599 { 600 if (message.Length >= 8) // sizeof(long) 601 { 602 // Try to recover remote win32 Exception. 603 long error = 0; 604 for (int i = 0; i < 8; ++i) 605 { 606 error = (error << 8) + message[i]; 607 } 608 609 ThrowCredentialException(error); 610 } 611 612 throw new AuthenticationException(SR.net_auth_alert, null); 613 } 614 615 if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeDoneId) 616 { 617 _remoteOk = true; 618 } 619 else if (_framer.ReadHeader.MessageId != FrameHeader.HandshakeId) 620 { 621 throw new AuthenticationException(SR.Format(SR.net_io_header_id, "MessageId", _framer.ReadHeader.MessageId, FrameHeader.HandshakeId), null); 622 } 623 624 CheckCompletionBeforeNextSend(message, lazyResult); 625 } 626 627 // 628 // This will check and logically complete the auth handshake. 629 // CheckCompletionBeforeNextSend(byte[] message, LazyAsyncResult lazyResult)630 private void CheckCompletionBeforeNextSend(byte[] message, LazyAsyncResult lazyResult) 631 { 632 //If we are done don't go into send. 633 if (HandshakeComplete) 634 { 635 if (!_remoteOk) 636 { 637 throw new AuthenticationException(SR.Format(SR.net_io_header_id, "MessageId", _framer.ReadHeader.MessageId, FrameHeader.HandshakeDoneId), null); 638 } 639 if (lazyResult != null) 640 { 641 lazyResult.InvokeCallback(); 642 } 643 644 return; 645 } 646 647 // Not yet done, get a new blob and send it if any. 648 StartSendBlob(message, lazyResult); 649 } 650 651 // 652 // This is to reset auth state on the remote side. 653 // If this write succeeds we will allow auth retrying. 654 // StartSendAuthResetSignal(LazyAsyncResult lazyResult, byte[] message, Exception exception)655 private void StartSendAuthResetSignal(LazyAsyncResult lazyResult, byte[] message, Exception exception) 656 { 657 _framer.WriteHeader.MessageId = FrameHeader.HandshakeErrId; 658 659 if (IsLogonDeniedException(exception)) 660 { 661 if (IsServer) 662 { 663 exception = new InvalidCredentialException(SR.net_auth_bad_client_creds, exception); 664 } 665 else 666 { 667 exception = new InvalidCredentialException(SR.net_auth_bad_client_creds_or_target_mismatch, exception); 668 } 669 } 670 671 if (!(exception is AuthenticationException)) 672 { 673 exception = new AuthenticationException(SR.net_auth_SSPI, exception); 674 } 675 676 if (lazyResult == null) 677 { 678 _framer.WriteMessage(message); 679 } 680 else 681 { 682 lazyResult.Result = exception; 683 IAsyncResult ar = _framer.BeginWriteMessage(message, s_writeCallback, lazyResult); 684 if (!ar.CompletedSynchronously) 685 { 686 return; 687 } 688 689 _framer.EndWriteMessage(ar); 690 } 691 692 _canRetryAuthentication = true; 693 ExceptionDispatchInfo.Throw(exception); 694 } 695 WriteCallback(IAsyncResult transportResult)696 private static void WriteCallback(IAsyncResult transportResult) 697 { 698 if (!(transportResult.AsyncState is LazyAsyncResult)) 699 { 700 NetEventSource.Fail(transportResult, "State type is wrong, expected LazyAsyncResult."); 701 } 702 703 if (transportResult.CompletedSynchronously) 704 { 705 return; 706 } 707 708 LazyAsyncResult lazyResult = (LazyAsyncResult)transportResult.AsyncState; 709 710 // Async completion. 711 try 712 { 713 NegoState authState = (NegoState)lazyResult.AsyncObject; 714 authState._framer.EndWriteMessage(transportResult); 715 716 // Special case for an error notification. 717 if (lazyResult.Result is Exception e) 718 { 719 authState._canRetryAuthentication = true; 720 ExceptionDispatchInfo.Throw(e); 721 } 722 723 authState.CheckCompletionBeforeNextReceive(lazyResult); 724 } 725 catch (Exception e) 726 { 727 if (lazyResult.InternalPeekCompleted) 728 { 729 // This will throw on a worker thread. 730 throw; 731 } 732 733 lazyResult.InvokeCallback(e); 734 } 735 } 736 ReadCallback(IAsyncResult transportResult)737 private static void ReadCallback(IAsyncResult transportResult) 738 { 739 if (!(transportResult.AsyncState is LazyAsyncResult)) 740 { 741 NetEventSource.Fail(transportResult, "State type is wrong, expected LazyAsyncResult."); 742 } 743 744 if (transportResult.CompletedSynchronously) 745 { 746 return; 747 } 748 749 LazyAsyncResult lazyResult = (LazyAsyncResult)transportResult.AsyncState; 750 751 // Async completion. 752 try 753 { 754 NegoState authState = (NegoState)lazyResult.AsyncObject; 755 byte[] message = authState._framer.EndReadMessage(transportResult); 756 authState.ProcessReceivedBlob(message, lazyResult); 757 } 758 catch (Exception e) 759 { 760 if (lazyResult.InternalPeekCompleted) 761 { 762 // This will throw on a worker thread. 763 throw; 764 } 765 766 lazyResult.InvokeCallback(e); 767 } 768 } 769 IsError(SecurityStatusPal status)770 internal static bool IsError(SecurityStatusPal status) 771 { 772 return ((int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory); 773 } 774 GetOutgoingBlob(byte[] incomingBlob, ref Exception e)775 private unsafe byte[] GetOutgoingBlob(byte[] incomingBlob, ref Exception e) 776 { 777 SecurityStatusPal statusCode; 778 byte[] message = _context.GetOutgoingBlob(incomingBlob, false, out statusCode); 779 780 if (IsError(statusCode)) 781 { 782 e = NegotiateStreamPal.CreateExceptionFromError(statusCode); 783 uint error = (uint)e.HResult; 784 785 message = new byte[sizeof(long)]; 786 for (int i = message.Length - 1; i >= 0; --i) 787 { 788 message[i] = (byte)(error & 0xFF); 789 error = (error >> 8); 790 } 791 } 792 793 if (message != null && message.Length == 0) 794 { 795 message = s_emptyMessage; 796 } 797 798 return message; 799 } 800 EncryptData(byte[] buffer, int offset, int count, ref byte[] outBuffer)801 internal int EncryptData(byte[] buffer, int offset, int count, ref byte[] outBuffer) 802 { 803 CheckThrow(true); 804 805 // SSPI seems to ignore this sequence number. 806 ++_writeSequenceNumber; 807 return _context.Encrypt(buffer, offset, count, ref outBuffer, _writeSequenceNumber); 808 } 809 DecryptData(byte[] buffer, int offset, int count, out int newOffset)810 internal int DecryptData(byte[] buffer, int offset, int count, out int newOffset) 811 { 812 CheckThrow(true); 813 814 // SSPI seems to ignore this sequence number. 815 ++_readSequenceNumber; 816 return _context.Decrypt(buffer, offset, count, out newOffset, _readSequenceNumber); 817 } 818 ThrowCredentialException(long error)819 internal static void ThrowCredentialException(long error) 820 { 821 Win32Exception e = new Win32Exception((int)error); 822 823 if (e.NativeErrorCode == (int)SecurityStatusPalErrorCode.LogonDenied) 824 { 825 throw new InvalidCredentialException(SR.net_auth_bad_client_creds, e); 826 } 827 828 if (e.NativeErrorCode == NegoState.ERROR_TRUST_FAILURE) 829 { 830 throw new AuthenticationException(SR.net_auth_context_expectation_remote, e); 831 } 832 833 throw new AuthenticationException(SR.net_auth_alert, e); 834 } 835 IsLogonDeniedException(Exception exception)836 internal static bool IsLogonDeniedException(Exception exception) 837 { 838 Win32Exception win32exception = exception as Win32Exception; 839 840 return (win32exception != null) && (win32exception.NativeErrorCode == (int)SecurityStatusPalErrorCode.LogonDenied); 841 } 842 } 843 } 844