Search code examples
c#credential-providerswinlogon

C# Custom Credential Provider RDP Issue


I am developing a C# implementation of custom credential provider. It's working with no problems on interactive sessions. However, when i try to connect that computer with RDP (mstsc), It gives an error message after credentials are serialized. Message is:

"An authentication error has occurred. The token supplied to the function is invalid.". In my server, GetSeralization method is like below;

public override int GetSerialization(out _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE pcpgsr, out _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcs, out string ppszOptionalStatusText, out _CREDENTIAL_PROVIDER_STATUS_ICON pcpsiOptionalStatusIcon)
{
    pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_NO_CREDENTIAL_NOT_FINISHED;
    pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();
    ppszOptionalStatusText = "";
    pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_NONE;

    var otpResult = DialogResult.Yes;

    // make OTP operation here

    if (otpResult == DialogResult.Yes)
    {
        CredHelper.Instance.RetrieveNegotiateAuthPackage(out var authPackage);

        var userNameField = credentialView.GetField(FieldTypeEnum.UsernameField);
        var passwordField = credentialView.GetField(FieldTypeEnum.PasswordField);

        var userNameSplitted = userNameField.Value.SplitSpecial('\\');

        if (userNameSplitted.Count <= 1)
        {
            ppszOptionalStatusText = "Failed to pack credentials";
            pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;
            return HResult.Fail;
        }

        pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_RETURN_CREDENTIAL_FINISHED;
        pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();

        NativeLogon.KerbInteractiveUnlockLogonInit(userNameSplitted.First(), userNameSplitted.Last(), passwordField.Value, (int)usageScenario, out KerbInteractiveUnlockLogon pkiul);

        NativeLogon.KerbInteractiveUnlockLogonPack(ref pkiul, out IntPtr inCredBuffer, out int inCredSize);

        ppszOptionalStatusText = string.Empty;
        pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_SUCCESS;
        pcpcs.clsidCredentialProvider = Statics.CredentialProviderGuid;

        pcpcs.rgbSerialization = inCredBuffer;
        pcpcs.cbSerialization = (uint)inCredSize;
        pcpcs.ulAuthenticationPackage = authPackage;

        return HResult.Ok;
    }

    ppszOptionalStatusText = "Failed to pack credentials";
    pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;
    return HResult.Fail;
}

My ICredentialProviderFilter implementation is below but I think its wrong

public int UpdateRemoteCredential(ref _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcsIn, out _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcsOut)
{
    pcpcsOut = pcpcsIn;

    return HResult.Ok;
}

I am stuck here. I cannot go forward. Thanks.


Solution

  • I solved the problem by changing C++ helper library for credential pack. In CredUI scenario, Kerberos ticket was incorrect. It should be like below;

    switch (scenario)
                    {
                    case 1: //CPUS_LOGON
                        pkil->MessageType = KerbInteractiveLogon;
                        hr = S_OK;
                        break;
                    case 2: //CPUS_UNLOCK_WORKSTATION
                        pkil->MessageType = KerbWorkstationUnlockLogon;
                        hr = S_OK;
                        break;
                    case 4: //CPUS_CREDUI
                        pkil->MessageType = KerbInteractiveLogon;
                        hr = S_OK;
                        break;
                    default:
                        hr = E_FAIL;
                        break;
                    }
    

    Now i can connect to remote machine.