Error while trying to create a Custom Windows Authentication Service

Jisan Anam 5 Reputation points
2024-10-24T08:37:13.0633333+00:00

I'm currently working on creating a Custom Windows Authentication System in Windows 11. I am using this GitHub project for starting reference. I've developed a DLL to implement a custom login layer on the Windows Login Tile. However, after entering a valid username and password in the tile fields, the system doesn't proceed to the next step—it loads for a while and then says "Incorrect username or password." Do you have any suggestions on how this issue can be resolved? Or can you help me find any other better way to create a Custom Windows Authentication flow (i.e. using custom fields, custom biometric devices, etc.)?

Code Snippet

 public List<_CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR> CredentialProviderFieldDescriptorList = new List<_CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR> {       \

 new _CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR

        {

            cpft = _CREDENTIAL_PROVIDER_FIELD_TYPE.CPFT_SMALL_TEXT,

            dwFieldID = 0,

            pszLabel = "Welcome to Custom Windows Login",

        },

        new _CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR

        {

            cpft = _CREDENTIAL_PROVIDER_FIELD_TYPE.CPFT_SUBMIT_BUTTON,

            dwFieldID = 1,

            pszLabel = "Login",

        },

        new _CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR

        {

            cpft = _CREDENTIAL_PROVIDER_FIELD_TYPE.CPFT_EDIT_TEXT, // Username field

            dwFieldID = FIELD_ID_USERNAME,

            pszLabel = "Enter Username",

        },

        new _CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR

        {

            cpft = _CREDENTIAL_PROVIDER_FIELD_TYPE.CPFT_PASSWORD_TEXT, // Password field

            dwFieldID = FIELD_ID_PASSWORD,

            pszLabel = "Enter Password",

        }

    };
public int GetSerialization(out _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE pcpgsr,
    out _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcs, out string ppszOptionalStatusText,
    out _CREDENTIAL_PROVIDER_STATUS_ICON pcpsiOptionalStatusIcon)
        {
            Log.LogMethodCall();

            // Hardcoded valid credentials
            string validUsername = "Reve";
            string validPassword = "3825568900";

            try
            {
                // Validate the username and password against hardcoded values
                if (username == validUsername && password == validPassword)
                {
                    // If valid, proceed with the authentication process
                    pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_RETURN_CREDENTIAL_FINISHED;
                    pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();

                    var inCredSize = 0;
                    var inCredBuffer = Marshal.AllocCoTaskMem(0);

                    if (!PInvoke.CredPackAuthenticationBuffer(0, username, password, inCredBuffer, ref inCredSize))
                    {
                        Marshal.FreeCoTaskMem(inCredBuffer);
                        inCredBuffer = Marshal.AllocCoTaskMem(inCredSize);

                        if (PInvoke.CredPackAuthenticationBuffer(0, username, password, inCredBuffer, ref inCredSize))
                        {
                            ppszOptionalStatusText = "Login successful";
                            pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_SUCCESS;

                            pcpcs.clsidCredentialProvider = Guid.Parse(Constants.CredentialProviderUID);
                            pcpcs.rgbSerialization = inCredBuffer;
                            pcpcs.cbSerialization = (uint)inCredSize;

                            RetrieveNegotiateAuthPackage(out var authPackage);
                            pcpcs.ulAuthenticationPackage = authPackage;

                            return HResultValues.S_OK;
                        }
                    }

                    Marshal.FreeCoTaskMem(inCredBuffer);
                    ppszOptionalStatusText = "Failed to pack credentials";
                    pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;
                    return HResultValues.E_FAIL;
                }
                else
                {
                    // If invalid, return an error message
                    ppszOptionalStatusText = "Invalid username or password";
                    pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;

                    // Indicate that the credential serialization failed
                    pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_NO_CREDENTIAL_NOT_FINISHED;
                    pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();

                    return HResultValues.E_FAIL;
                }
            }
            catch (Exception ex)
            {
                // Handle any unexpected exceptions
                ppszOptionalStatusText = $"An error occurred: {ex.Message}";
                pcpsiOptionalStatusIcon = _CREDENTIAL_PROVIDER_STATUS_ICON.CPSI_ERROR;
                pcpgsr = _CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE.CPGSR_NO_CREDENTIAL_NOT_FINISHED;
                pcpcs = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION();
                return HResultValues.E_FAIL;
            }
        }

```**Error Message**

|An account failed to log on.  
Subject:  
Security ID: SYSTEM  
Account Name: DESKTOP-476EOJ1$  
Account Domain: WORKGROUP  
Logon ID: 0x3E7  
  
Logon Type: 2  
Account For Which Logon Failed:  
Security ID: NULL SID  
Account Name: -  
Account Domain: -  
Failure Information:  
Failure Reason: Unknown user name or bad password.  
Status: 0xC000006D  
Sub Status: 0xC000006A  
Process Information:  
Caller Process ID: 0x860  
Caller Process Name: C:\Windows\System32\svchost.exe  
Network Information:  
Workstation Name: -  
Source Network Address: 127.0.0.1  
Source Port: 0  
Detailed Authentication Information:  
Logon Process: User32   
Authentication Package: Negotiate  
Transited Services: -  
Package Name (NTLM only): -  
Key Length: 0  
This event is generated when a logon request fails. It is generated on the computer where access was attempted.|
| -------- |
|An account failed to log on. Subject: Security ID: SYSTEM Account Name: DESKTOP-476EOJ1$ Account Domain: WORKGROUP Logon ID: 0x3E7 Logon Type: 2 Account For Which Logon Failed: Security ID: NULL SID Account Name: - Account Domain: - Failure Information: Failure Reason: Unknown user name or bad password. Status: 0xC000006D Sub Status: 0xC000006A Process Information: Caller Process ID: 0x860 Caller Process Name: C:\Windows\System32\svchost.exe Network Information: Workstation Name: - Source Network Address: 127.0.0.1 Source Port: 0 Detailed Authentication Information: Logon Process: User32 Authentication Package: Negotiate Transited Services: - Package Name (NTLM only): - Key Length: 0 This event is generated when a logon request fails. It is generated on the computer where access was attempted.|

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,029 questions
0 comments No comments
{count} vote

1 answer

Sort by: Most helpful
  1. Jiale Xue - MSFT 46,556 Reputation points Microsoft Vendor
    2024-10-25T06:34:06.8066667+00:00

    Hi @Jisan Anam , Welcome to Microsoft Q&A,

    The error message says "Unknown username or bad password". This indicates that the credentials were not correctly serialized or passed to the authentication package, causing the login attempt to fail.

    Errors can occur when you try to package and pass credentials for authentication. Specifically, the CredPackAuthenticationBuffer function may not correctly serialize the username and password into the format required by the authentication system. Please ensure that: The username and password variables contain the correct input values ​​from the login tile. Buffer allocation (inCredBuffer) and size (inCredSize) are handled correctly. If CredPackAuthenticationBuffer fails, check the return value and possibly use Marshal.GetLastWin32Error() to determine the specific reason for the failure.

    The system expects the username and password "Reve" and "3825568900" in your GetSerialization method. Make sure that the username and password entered from the login tile exactly match the hard-coded values. Otherwise, the system will always return "Invalid username or password". For debugging purposes, you can temporarily add logging to print out input values ​​compared to hard-coded values.

    Windows Authentication is security-intensive. The system expects credentials to be packaged and presented to the Local Security Authority (LSA) in a format that the system can understand. If the "CredPackAuthenticationBuffer" or subsequent serialization does not match the expected format, the logon attempt will fail. Make sure that the "_CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION" structure and its fields are populated correctly before passing them to the authentication system.

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.