/// <summary> /// Helper method for legacy implementation. /// </summary> public virtual NTStatus GetNtlmChallengeMessage(out GssContext?context, NegotiateMessage negotiateMessage, out ChallengeMessage?challengeMessage) { IGssMechanism?ntlmAuthenticationProvider = FindMechanism(NtlmSspIdentifier); if (ntlmAuthenticationProvider != null) { context = new GssContext(ntlmAuthenticationProvider, null); NTStatus result = ntlmAuthenticationProvider.AcceptSecurityContext(ref context.MechanismContext, negotiateMessage.GetBytes(), out byte[] outputToken); challengeMessage = new ChallengeMessage(outputToken); return(result); } context = null; challengeMessage = null; return(NTStatus.SEC_E_SECPKG_NOT_FOUND); }
public virtual NTStatus AcceptSecurityContext(ref GssContext?context, byte[] inputToken, out byte[]?outputToken) { outputToken = null; SimpleProtectedNegotiationToken?spnegoToken = null; try { spnegoToken = SimpleProtectedNegotiationToken.ReadToken(inputToken, 0, false); } catch { // ignored } if (spnegoToken != null) { if (spnegoToken is SimpleProtectedNegotiationTokenInit tokenInit) { if (tokenInit.MechanismTypeList.Count == 0) { return(NTStatus.SEC_E_INVALID_TOKEN); } // RFC 4178: Note that in order to avoid an extra round trip, the first context establishment token // of the initiator's preferred mechanism SHOULD be embedded in the initial negotiation message. byte[] preferredMechanism = tokenInit.MechanismTypeList[0]; IGssMechanism?mechanism = FindMechanism(preferredMechanism); bool isPreferredMechanism = (mechanism != null); if (!isPreferredMechanism) { mechanism = FindMechanism(tokenInit.MechanismTypeList); } if (mechanism == null) { return(NTStatus.SEC_E_SECPKG_NOT_FOUND); } NTStatus status; context = new GssContext(mechanism, null); if (isPreferredMechanism) { status = mechanism.AcceptSecurityContext(ref context.MechanismContext, tokenInit.MechanismToken, out byte[] mechanismOutput); outputToken = GetSpnegoTokenResponseBytes(mechanismOutput, status, mechanism.Identifier); } else { status = NTStatus.SEC_I_CONTINUE_NEEDED; outputToken = GetSpnegoTokenResponseBytes(null, status, mechanism.Identifier); } return(status); } else // SimpleProtectedNegotiationTokenResponse { if (context == null) { return(NTStatus.SEC_E_INVALID_TOKEN); } IGssMechanism mechanism = context.Mechanism; SimpleProtectedNegotiationTokenResponse tokenResponse = (SimpleProtectedNegotiationTokenResponse)spnegoToken; NTStatus status = mechanism.AcceptSecurityContext(ref context.MechanismContext, tokenResponse.ResponseToken, out byte[] mechanismOutput); outputToken = GetSpnegoTokenResponseBytes(mechanismOutput, status, null); return(status); } } // [MS-SMB] The Windows GSS implementation supports raw Kerberos / NTLM messages in the SecurityBlob. // [MS-SMB2] Windows [..] will also accept raw Kerberos messages and implicit NTLM messages as part of GSS authentication. if (!AuthenticationMessageUtils.IsSignatureValid(inputToken)) { return(NTStatus.SEC_E_INVALID_TOKEN); } MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(inputToken); IGssMechanism? ntlmAuthenticationProvider = FindMechanism(NtlmSspIdentifier); if (ntlmAuthenticationProvider == null) { return(NTStatus.SEC_E_SECPKG_NOT_FOUND); } if (messageType == MessageTypeName.Negotiate) { context = new GssContext(ntlmAuthenticationProvider, null); } if (context == null) { return(NTStatus.SEC_E_INVALID_TOKEN); } return(ntlmAuthenticationProvider.AcceptSecurityContext(ref context.MechanismContext, inputToken, out outputToken)); }