Share via


The Windows Negotiation Extension and Writing NegoEx SSPs

Dave McPherson

Microsoft Corporation

Introduction
SSPI
Security Package Negotiation
NegoEx Architecture
     NegoEx
     NegoEx Credential Management
     NegoEx Compatible Credential Providers
     NegoEx SSP Selection
Implementing a NegoEx Compatable SSP
     Elements of a NegoEx Compatible SSP
          Boot Time Initialization
          The Authentication Ceremony
          Metadata Exchange
          Credential Collection
          Creating a Logon Session
          Creating a Token
     Installing and Registering a NegoEx Compatible SSP
Implementing a NegoEx Compatible Credential Provider
     Updates to SetSerializaton
     Updates to GetSerializaton
Appendix A: The SECPKG_FUNCTION_TABLE_V5
Appendix B: The LSA_SECPKG_FUNCTION_TABLE

Introduction

In Windows 2000, Microsoft introduced native support for the Kerberos authentication protocol. While NTLM was still available, Kerberos became the preferred authentication protocol for Windows authentication. Because many existing servers and applications depended on NTLM behavior, Microsoft provided support for the negotiation of NTLM and Kerberos through the use of the Security Support Provider Interface (SSPI), and the Simple and Protected GSS-API Negotiation Mechanism protocol (SPNego.)

SSPI and SPNego provided the ability to negotiate between Kerberos and NTLM through the use of the Security Support Package (SSP.) An SSP is an implementation of common application security features such as an authentication protocol and encryption services. Both Kerberos and NTLM were implemented in Windows 2000 as SSPs. The Negotiate protocol, which was also implemented as an SSP, managed the process of selecting between Kerberos and NTLM based on the support for each available on the client and server machines and the domain controller.

Additionally, SSPI provided a common programming runtime for applications to use to avoid having to write code directly to an authentication package. By writing to SSPI and specifying the "Kerberos" SSP, an application could use the Kerberos security package. Additional SSPs could be written and installed to leverage the SSPI common interfaces for authentication support. Digest and the Schannel/TLS SSPs are examples of additional SSPs later provided in Windows. However, prior to Windows 7, the Negotiate SSP was specifically designed to support negotiation between Kerberos and NTLM only. Digest, Schannel, and other installed SSPs were not negotiable. Applications and components that used SSPI and the negotiate security package could not use additional SSPs unless they wrote specific code for those SSPs.

Today, as the industry turns to hosted services and federated scenarios, additional authentication protocols are often used in these scenarios, and support for such authentication protocols is needed. As new authentication protocols are being introduced, integration with existing applications that leverage the Windows platform for authentication is required. The Windows 7 Negotiate extension (NegoEx) enhances the Windows Negotiate mechanism to allow for the creation and installation of new negotiable security support packages. Through the Windows 7 Negotiation extension, the newer authentication mechanisms provided by the system can be extended to existing Windows applications in a seamless and transparent fashion, through integration with existing platform security interfaces such as SSPI and SSP.

SSPI

SSPI provides a common API to allow applications to use multiple security packages with little to no modification. This is especially true for applications that use Kerberos and NTLM. Applications that use other security packages may have to vary more in usage of SSPI. The following diagram illustrates the relationship of SSPI to applications and security packages installed on a Windows system.

Ff468736.sspi(en-us,MSDN.10).gif

To facilitate an application's interactions with authentication protocols, SSPI uses the abstractions of credentials and security contexts. Credentials are data that can be used to authenticate a security principal, such as a user name, password, or certificate. In an SSPI client and server scenario, each party provides some type of credentials. These credentials are used by SSPI to perform the authentication process. A security context is a collection of authentication data about a security principal for an instance of a session.

Throughout the SSPI authentication process, the client and server pass partial context information between each other in the form of security BLOBs. In this process, the SSPI client and server each initially attain credentials and then appropriately call SSPI to create security BLOBs that must be sent to the counterpart. Likewise, when an SSPI client or server receives a security BLOB from the other, it will use SSPI to process and incorporate the security BLOB (which contains authentication protocol specific data) into the context for the authenticated relationship.

The SSPI authentication process or "ceremony" involves the client and server each sending and receiving security BLOBs until authentication has succeeded or failed.

The result of a successful SSPI authentication ceremony will be the client and the server each having a security context that establishes an authenticated relationship with the other. These security contexts do not contain the credentials used to create them, but can contain information that results from the authentication process that may be useful to the application for securing communications (such as an encryption key) or maintaining the authenticated connection (such as a Kerberos ticket or certificate) or information that may be useful in authorizing the client's request (such as security claims about the client.) The exact contents of the context are determined by the SSP that is used to perform the authentication.

The following diagram (adapted from Programming Server-Side Applications for Microsoft Windows 2000 by Jeffrey Richter and Jason D. Clark) summarizes the flow of the SSPI authentication ceremony as it takes place on the client (left) and server (right).

Ff468736.SSPIAuth(en-us,MSDN.10).gif

In the call to AcquireCredentialsHandle, the credentials are passed from the application to the SSP through the SEC_WINNT_AUTH_IDENTITY structure (by using the pAuthData parameter.) Throughout the authentication ceremony, the client and server receive security BLOBs and package them into security buffers to be sent to the selected SSP. These buffers are sent between the application and the SSP through the SecBuffer structure sent into the InitializeSecurityContext and AcceptSecurityContext functions. Each of these functions takes a pInput and pOutput parameter which contains an array of SecBuffer structures. The SSP will then use this data to continue the authentication ceremony.

Security Package Negotiation

Because Windows supports both NTLM and Kerberos and certain applications depend on a specific protocol while others can support both, Windows supports protocol negotiation between the client and the server before the actual authentication takes place. To enable negotiation of protocols, Microsoft included a special SSP called Negotiate. This package implements protocol negotiation based on the Simple and Protected GSS-API Negotiation Mechanism (SPNEGO) as defined in the RFC 2478.

The Negotiate SSP does not implement authentication or encryption support, as other SSPs do. Instead, Negotiate attempts to determine and use the strongest authentication protocol available to both the client and server. Prior to Windows 7, the Negotiate SSP can only negotiate between the Kerberos and NTLM packages.

The Negotiate SSP works as follows. Client applications that use SSPI specify the Negotiate SSP instead of Kerberos or NTLM. The client Negotiate package then sends a list of available SSPs to the server. Finally, the server Negotiate package picks an SSP based on its locally available SSPs and communicates it to the client. This negotiation process is usually optimized for Kerberos through the use of an optimistic token. This optimization involves the attachment of a Kerberos authentication message (token) along with the list of supported security packages in the client's first step of negotiation. More information about Microsoft's implementation of SPNEGO can be found at: https://msdn.microsoft.com/en-us/library/cc247021%28PROT.10%29.aspx.

An important architectural element that distinguishes Negotiate, NTLM and Kerberos from the other SSPs shown above, is that both Negotiate and the SSPs that are Negotiable (prior to Windows 7 only NTLM and Kerberos) will run within the Local Security Authority (LSA) process. Not the context of the user mode process itself (the following diagram illustrates this). This allows the protocols and credentials and the keys they use to be protected from processes running in the context of the user. However, because a fault in the LSA process will cause a fault in the operating system, this also puts a greater burden on the SSP developer to ensure the stability of the SSP.

Ff468736.negoexapp(en-us,MSDN.10).gif

For more information about SSP negotiation, see the NegoAuth sample in the Windows SDK.

The Negotiate package has been used extensively to negotiate authentication protocols prior to Windows 7. However, the limitations of SPNEGO as implemented in Windows prevents negotiation of more advanced authentication protocols that are required in certain scenarios.

Among these limitations is that SPNEGO does not allow for the authentication packages to send auxiliary data that can be used in the process of negotiating the authentication protocol. Auxiliary data, often referred to as authentication metadata, can embody a variety of information based on the potential authentication packages. This data can contain information that can be used by the authentication protocols or the end user to perform authentication or any one of a set of potential options. Another limitation of SPNEGO is that it does not allow a protocol to be negotiated after the first roundtrip. This limitation prevents scenarios in which the client requests policy from the server, and uses that policy to determine which protocol to use.

NegoEx Architecture

Due to the limitations mentioned above, Windows 7 introduces an enhancement to Negotiate to enable use of new security packages for new scenarios.

NegoEx

The NegoEx protocol is documented in what is currently IETF draft-zhu-negoex-01. This section describes the integration of NegoEx within the Windows SSPI and Negotiate architecture.

NegoEx is implemented as a new SSP that can be negotiated by the Negotiate SSP. Like Negotiate, NegoEx will be loaded into LSA at boot time. NegoEx extends the Negotiation mechanism through the addition of another negotiable SSP. To do this, in Windows 7, the Negotiate SSP has been modified to support the negotiation of the NegoEx SSP. When the Negotiate SSP negotiates which SSP to use, the Negotiate SSP will now call into NegoEx to determine whether it, through one of the installed SSPs designed for NegoEx, can support the requested authentication. Within NegoEx, negotiations are done between each NegoEx negotiable security package. The following diagram illustrates the relationship between the Negotiate SSP, the existing SSPs, and new SSPs that are designed to work under NegoEx. This diagram references PKU2U, which is a new SSP that is included in Windows 7.

Ff468736.pku2u(en-us,MSDN.10).gif

To use NegoEx, applications will still specify the "Negotiate" package and can still use the same negotiation logic as described above, except when user prompting is needed and in what is called a server-first scenario (which is new to NegoEx, existing SSPI applications do not use this). Therefore, existing applications that use SPNego may not need to change to support NegoEx, depending on whether the applications need to prompt the user for credentials.

To maintain backward compatibility with existing scenarios, Kerberos remains the favored protocol when NegoEx is used. If Kerberos indicates to the Negotiate SSP that it can service an authentication request, then it will be selected before NegoEx SSPs are attempted. In situations where Kerberos must not be used, a server application can avoid Kerberos by calling the SspiExcludePackage API. Package exclusion should be done on the server-side and should be done through configuration options to avoid having applications being written with hard-coded exclusions of packages.

NegoEx Credential Management

While NegoEx and SSPs do not directly initiate credential prompting user interfaces, various scenarios do include situations where credential collection or selection prompting is required. In these situations, an application using SSPI's call to InitializeSecurityContext() fails with an error that tells the caller that credentials are required. Several errors may imply that prompting is needed. In Windows 7, SSPI applications should use the SspiIsPromptingNeeded() API to interpret the return value from InitializeSecurityContext() to determine whether a prompt is needed. If prompting is needed, the application should use the SspiPromptForCredentials() API to prompt the user for credentials. In situations where credential prompting is managed by network transport functions (for example, WinINet), the application should reattempt the network call and request that the transport layer prompt the user for credential input (for example, by calling the InternetErrorDlg function of the WinINet API).

NegoEx Compatible Credential Providers

Certain scenarios require support for authentication protocols in which the server being accessed may provide policy to the client. Such policy may indicate that the credentials supplied by the client must conform to a specific form. For example, a server may require that a certain name claim exists in the supplied credential token, or the server may require credentials from a specific identity provider. To support this policy driven credential collection model, the Windows credential provider framework is extended in Windows 7 to allow the processing of the policy to be reflected in the credential options presented to the user. To support this scenario and to minimize changes to applications using SSPI, SspiPromptForCredentials() retrieves the policy from the SSP by a query into the SSP based on the target name specified (the name of the remote service to which the client is authenticating).

The following diagram illustrates the functional relationship between a NegoEx compatible credential provider and a NegoEx compatible SSP.

Ff468736.CredProvSSP(en-us,MSDN.10).gif

When an SSPI application determines that prompting is needed, it must call SspiPromptForCredentials() and specify the target name. The SspiPromptForCredentials() call will retrieve the policy from the SSP, based on the given target name, and provide the policy to each credential provider. NegoEx compatible credential providers will determine whether they can support the credential type requested. If multiple providers support the requested credential type, each provider's tile will be displayed to the user in the system credential collection dialog box. The user will choose which tile (it is expected that typically only one installed credential provider will support the credential type requested, and the user won't have to choose) and enter user credentials. When the credentials are returned from SspiPromptForCredentials(), they can be copied by value (potentially to be stored by the application). The application then supplies the credentials handle to AcquireCredentialsHandle() to resume the security context creation begun in earlier calls to InitializeSecurityContext().

NegoEx SSP Selection

NegoEx starts the SSPI context negotiation with a NegoEx protocol operation called the metadata exchange. In this operation, data from all NegoEx compatible SSPs is queried on the party initiating the authentication (the client or server) and then processed on the peer. Each SSP analyzes the data to determine whether the metadata implies that the SSP can or cannot service the authentication request. If an SSP cannot service the request, it will return an error to NegoEx. If there is no SSP available after the metadata exchange, the context negotiation fails with error SEC_E_NO_CREDENTIALS.

Otherwise, if there is one and only one SSP that is available after the metadata exchange, that SSP is selected. If the SSP needs user interaction because it does not have credentials that meet the criteria specified by the server, the SEC_I_INCOMPLETE_CREDENTIALS error is returned. This is when SspiPromptForCredentials must be called by the SSPI application to collect the user credentials. If this SSP has credentials available (for example stored credentials), then the NegoEx picks this SSP, and the authentication ceremony proceeds silently (without prompting the user for credential entry).

If there is more than one SSP that is capable of servicing the authentication request after the metadata exchange, and at least one of the SSPs does not need user interaction, the SSP that does not need user interaction is selected. If more than one SSP does not need user interaction, the first SSP in the preference order specified by the server is selected. The preference order on the server is the package order for Negotiate, and it is a per-machine policy configured in the registry.

When there is more than one SSP available and each of these needs user interaction, then NegoEx will return error SEC_I_INCOMPLETE_CREDENTIALS (by using InitializeSecurityContext()) and SspiPromptForCredentials() must be called by the SSPI application to collect the user credentials. In the system credential collection dialog box, each supported credential type is presented as a credential provider tile. The display order of the credential provider tiles is determined locally by the client machine.

Implementing a NegoEx Compatable SSP

A NegoEx compatible SSP is a system DLL that will be called by NegoEx during the negotiation process. A NegoEx compatible SSP must implement a set of functions known as the Security Package Management Interface version 5 (SPMI V5.) All NegoEx compatible SSPs are loaded by the LSA when the system boots. You can choose to implement a NegoEx SSP if you want to provide a new authentication protocol that will be supported by the system protocol negotiation process that is used by many applications and system components. In addition to implementing an authentication protocol, a NegoEx compatible SSP must properly participate in the Negotiation process. If a NegoEx compatible SSP does not cooperate correctly, negotiation process failure, application compatibility failure, or a system crash may result.

Elements of a NegoEx Compatible SSP

Writing a NegoEx compatible SSP involves implementing the same SPMI functions as in prior releases, as well as a set of four additional new functions. SPMI functions for SSPs are documented in the Windows SDK (these function tables are listed in Appendix A).

Boot Time Initialization

As Windows boots, each NegoEx compatible SSP is loaded into the LSA process. At this time, the LSA queries each SSP to determine whether it is a NegoEx compatible SSP. The LSA then queries the SSP for a function table, giving the LSA pointers to each function that the SSP has implemented.

The following diagram illustrates the initialization process.

Ff468736.lsamodeinit(en-us,MSDN.10).gif

At system startup, the LSA calls the SpLsaModeInitialize() function in each SSP to retrieve pointers to the functions implemented by each SSP within the SSP DLL. The function pointers are passed to the LSA in an array of SECPKG_FUNCTION_TABLE structures. NegoEx compatible SSPs must provide SECPKG_FUNCTION_TABLE_V5 (or greater) structures.

Note that several of the functions in the SECPKG_FUNCTION_TABLE require the SSP to allocate memory that the LSA will later free. Therefore, the memory allocation function used in the SSP must correspond to the memory deallocation function used by the LSA. An SSP implementer must use the proper memory allocation function for each memory allocation for which the LSA will free its memory. To determine the proper memory allocation function to use, see the Windows SDK documentation for each function.

Ff468736.lsa(en-us,MSDN.10).gif

After receiving the set of SECPKG_FUNCTION_TABLE structures, the LSA calls the SpInitialize() function of each security package. The LSA uses this function call to pass each security package an LSA_SECPKG_FUNCTION_TABLE structure, which contains pointers to the LSA support functions available to security packages. In addition to storing the pointers to the LSA support functions, custom security packages should use their implementation of the SpInitialize() function to perform any initialization related processing (see Appendix B). The functions in this table provide the SSP with means of communicating with the LSA as well as with client applications that need data from the SSP. For more information, see the documentation for each of these functions in the Windows SDK.

After the above steps, NegoEx gets a notification that a new package has loaded. At this point, NegoEx checks to determine whether the package has NegoEx specific capabilities. To do so, NegoEx calls the SSPs SpGetInfo function. The SpGetInfo function reports the capabilities of the package, such as whether it supports mutual auth, and whether it is a NegoEx package (SECPKG_FLAG_NEGOTIABLE2). If the SSP supports NegoEx, the package is added to its list of NegoEx packages.

NegoEx then queries for the extended information by using the SpGetExtendedInformation() function. A NegoEx compatible SSP should support the query for SecpkgNego2Info. In response to this query, the NegoEx compatible SSP must return the AuthScheme (also called the CredType) it supports. The AuthScheme is a GUID which is package specific.

The Authentication Ceremony

After boot time initialization, NegoEx waits for an authentication ceremony to begin. After NegoEx gets the initial authentication request as part of the first call to InitializeSecurityContext() or AcceptSecurityContext(), NegoEx attempts to create the initial NegoEx message with a list of NegoEx packages it supports. The initial NegoEx message is referred to in section 5.1 of the NegoEx RFC. NegoEx calls the AcquireCredentialsHandle() function of each NegoEx compatible SSP, passing in the supplied or default credentials. Depending on whether AcquireCredentialsHandle() succeeds, the NegoEx package is included or excluded from the initial NegoEx message.

Metadata Exchange

The second task of the NegoEx compatible SSP is to respond to the metadata exchange process that takes place at the beginning of the protocol negotiation. The metadata exchange involves NegoEx calling SpQueryMetaData() on the side of the negotiation that initiates the authentication ceremony and then calling a corresponding SpExchangeMetadata() on the communicating peer.

NTSTATUS NTAPI
SpQueryMetaData
    __in_opt LSA_SEC_HANDLE CredentialHandle,
    __in_opt PUNICODE_STRING TargetName,
    __in ULONG ContextRequirements,
    __out PULONG MetaDataLength,
    __deref_out_bcount(*MetaDataLength) PUCHAR* MetaData,
    __inout PLSA_SEC_HANDLE ContextHandle
    )

NegoEx calls the SpQueryMetaData() function of each NegoEx compatible SSP, and each SSP may or may not return metadata. The metadata is specific to the SSP and will be simply passed to the peer. If the SSP on the session initiating system returns metadata, that data will be sent to the peer. On the peer, NegoEx will receive this metadata in the negotiation message and will call SpExchangeMetaData(), which will send the metadata to each NegoEx compatible SSP. If there is no metadata to be returned, the function will return success with an empty output token (the MetaData parameter). If SpQueryMetaData fails with SEC_E_NO_CREDENTIALS for a particular NegoEx compatible SSP, NegoEx will remove that SSP from the set of SSPs to be negotiated.

NTSTATUS NTAPI
            
SpExchangeMetaData(
    __in_opt LSA_SEC_HANDLE CredentialHandle,
    __in_opt PUNICODE_STRING TargetName,
    __in ULONG ContextRequirements,
    __in ULONG MetaDataLength,
    __in_bcount(MetaDataLength) PUCHAR MetaData,
    __inout PLSA_SEC_HANDLE ContextHandle
    )

NegoEx calls the SpExchangeMetadata() function to process any metadata received from the peer.

It then calls SpQueryMetadata() to generate the metadata token from this end of the conversation. If there is no metadata to be returned, the function will return success with an empty output token (the MetaData parameter). If SpExchangeMetaData() on a particular SSP fails with an error (that is, if the macro: NT_SUCCESS(status) returns false), NegoEx removes the SSP from the set of SSPs to be negotiated.

Credential Collection

As stated above, a requirement that necessitates the Windows 7 NegoEx extension is enhanced credential collection capabilities that include context based credential prompting that is driven by metadata supplied from the server. To facilitate this enhancement, the credential provider framework was extended in Windows 7 to allow communication of the metadata between the NegoEx compatible SSP and a corresponding credential provider.

When an SSP has indicated in the metadata exchange phase that it can potentially service the authentication request, the SSP may still require that credentials be provided to complete the authentication ceremony. NegoEx queries whether an SSP needs credentials by calling SpQueryContextAttributes(SECPKG_ATTR_PROMPTING_NEEDED).

If the SpQueryContextAttributes(SECPKG_ATTR_PROMPTING_NEEDED) call returns with STATUS_NOT_FOUND, then no user credential prompt is needed for a given security context.

If SpQueryContextAttribute(SECPKG_ATTR_PROMPTING_NEEDED) returns SUCCESS, and returns a SecPkgContext_CredInfo structure, this indicates whether credentials are needed (typically retrieved by prompting the user) to complete the authentication for this security context. If credentials are needed, NegoEx returns SEC_E_NO_CREDENTIALS to the application, which should then process the returned error code by using the SspiIsPromptingNeeded() API and then prompt the user for credentials accordingly. No other return code is expected from the SECPKG_ATTR_PROMPTING_NEEDED query.

When credentials are needed, the application calls SspiPromptForCredentials(), which invokes the credential provider passing in the target name. SspiPromptForCredentials() does a look up of the context based upon the target name, and creates a marshaled context which is sent to the credential provider. The credential provider un-marshals the credential context sent by SspiPromptForCredentials(). It then queries the SSP for any SSP specific data needed in the credential collection process (such as a bitmap for a credential title). To make the query, the credential provider calls the SspiGetCredUIContext() method, which causes the LSA to call the SpGetCredUIContext() function of the SSP.

NTAPI
SpGetCredUIContext(
    __in LSA_SEC_HANDLE ContextHandle,
    __in GUID* CredType,
    __in ULONG FlatCredUIContextLength,
    __in_bcount(FlatCredUIContextLength) PUCHAR * FlatCredUIContext
    );

NegoEx calls this function to retrieve the context information that will be passed to the credential provider to customize the credential collection UI for this given security context. If the SSP does not choose to prompt, SpGetCredUIContext() is not called by NegoEx. The ContextHandle parameter contains the security context handle. The CredType parameter identifies the credential type supported by the SSP. It is expected that there is a one to one mapping between the credential provider and the SSP in terms of the CredType that it supports. The FlatCredUIContext receives package specific information for the security context of the given credential type.

SpUpdateCredentials() is invoked on an SSP from a credential provider, when the SSP should change the state of a specified security context.

NTAPI
SpUpdateCredentials(
    __in LSA_SEC_HANDLE ContextHandle,
    __in GUID* CredType,
    __in ULONG FlatCredUIContextLength,
    __in_bcount(FlatCredUIContextLength) PUCHAR FlatCredUIContext
    );

When a credential provider calls SspiUpdateCredential(), which calls into NegoEx, NegoEx calls SpUpdateCredentials() to update the context based on credential data that was collected from the user. Updating the security context is secured by an ACL, and, to update the security context, the caller (typically a credential provider) must either be running in the local system context (in the case of secure desktop prompting) or have equivalent credentials as that of the security context.

The ContextHandle parameter contains the security context handle. The CredType parameter identifies the credential type. FlatCredUIContext contains the data returned by the credentials provider.

The above API can be called multiple times for updating the client security context.

Creating a Logon Session

One of the responsibilities of an authentication package is to create a logon session when a user's logon request is authenticated. A logon session is a data structure managed by the kernel that stores credentials, credential data, or an authenticated security principal. Any process that is running as the authenticated principal will be associated with this logon session. Thus, the logon session is used to facilitate single-sign-on (SSO) because a process that is launched by processes associated with the logon session will not require credentials.

An SSP can create a logon session by calling CreateLogonSession(). This will typically be done in the SSP's implementation of the SpAcceptLsaModeContext() function, after the authentication has succeeded. In calling this function, the SSP must provide a locally unique logon identifier that identifies the session. Use NtAllocateLocallyUniqueId() to create this identifier. When successful, this function returns a logon identifier (LUID) that uniquely identifies the session. For more information about the CreateLogonSession() function, see the Windows SDK.

Creating a Token

When a logon session has been created for a particular security principal, the server side SSP must create a Windows NT access token for the authenticated client security principal. The Windows NT access token must have the same authentication ID as the logon ID of the logon session described in the previous session. When the last token reference for the token is closed, the logon session is released by LSA. The token and the logon session are logically linked by the logon ID.

To create a Windows NT access token, the SSP calls the CreateToken() function. When calling this function, you should specify a structure type of LSA_TOKEN_INFORMATION_V2 for the TokenInformation parameter, and LsaTokenInformationV2 for the TokenInformationType parameter. The structure is identical to the V1 token information structure, with the exception that all the memory used is within a continuous buffer. The TokenInformation structure must be allocated by using the AllocateLsaHeap() function. For more information about the CreateToken() function and memory management functions used by an SSP, see the Windows SDK.

Installing and Registering a NegoEx Compatible SSP

After developing an SSP, you must register it. To do so, add the name of your custom SSP DLL to the data of the following registry value:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Security Packages

The data for this registry value is a list of the names of SSP DLLs, without the .dll extension. The data type for this list is REG_MULTI_SZ, so there must be a null character ('\0') between each DLL name in the list.

The DLL itself should be placed in the \System32 directory, and a WOW version (32-bit version for x86 callers on x64) should be placed in \Windows\System32\Syswow64.

Each time the system starts, the LSA loads the SSP DLLs in this list (in the order listed in the registry) and performs the initialization sequence described in Boot Time Initialization. An MSI can add an SSP without reboot by using the AddSecurityPackageW() API. An update of an SSP requires a reboot of the system.

Implementing a NegoEx Compatible Credential Provider

A Windows 7 credential provider is typically required for any prompting scenario that involves a NegoEx compatible SSP. Implementing a credential provider is described in the Windows SDK. However, a NegoEx compatible SSP must support a credential type that the SSP supports (as discussed in the Credential Collection section above) and must appropriately call some additional interfaces as described below.

Updates to SetSerialization

When the credential provider is invoked, the credential provider must call SspiUnmarshalCredUIContext() and check the returned structure for any credential types it supports. The credential provider would then call SspiGetCredUIContext() for each credential type it supports to determine whether a tile should be shown for that credential type. The credential provider can optionally call SspiUpdateCredentials() to update the credentials maintained in the SSP.

Updates to GetSerialization

On this call, the credential provider is expected to a return a PSEC_WINNT_OPAQUE identity BLOB back to the caller.

For more information about implementing a NegoEx compatible credential provider, see the Sample NegoEx Credential Provider in the Windows SDK.

Appendix A: The SECPKG_FUNCTION_TABLE_V5

The SECPKG_FUNCTION_TABLE_V5 must be implemented by a NegoEx SSP. The SECPKG_FUNCTION_TABLE_V5 contains the set of function pointers that the SSP must implement and that will be called by the LSA when each function is required by the LSA. For more information about each of these functions, see the Windows SDK.

typedef struct SECPKG_FUNCTION_TABLE_V5 {
  PLSA_AP_INITIALIZE_PACKAGE        InitializePackage;
  PLSA_AP_LOGON_USER            LogonUser;
  PLSA_AP_CALL_PACKAGE          CallPackage;
  PLSA_AP_LOGON_TERMINATED      LogonTerminated;
  PLSA_AP_CALL_PACKAGE_UNTRUSTED        CallPackageUntrusted;
  PLSA_AP_CALL_PACKAGE_PASSTHROUGH      CallPackagePassthrough;
  PLSA_AP_LOGON_USER_EX         LogonUserEx;
  PLSA_AP_LOGON_USER_EX2            LogonUserEx2;
  SpInitializeFn *          Initialize;
  SpShutdownFn *                Shutdown;
  SpGetInfoFn *             GetInfo;
  SpAcceptCredentialsFn *           AcceptCredentials;
  SpAcquireCredentialsHandleFn *        AcquireCredentialsHandle;
  SpQueryCredentialsAttributesFn *      QueryCredentialsAttributes;
  SpFreeCredentialsHandleFn *       FreeCredentialsHandle;
  SpSaveCredentialsFn *         SaveCredentials;
  SpGetCredentialsFn *          GetCredentials;
  SpDeleteCredentialsFn *           DeleteCredentials;
  SpInitLsaModeContextFn *      InitLsaModeContext;
  SpAcceptLsaModeContextFn *        AcceptLsaModeContext;
  SpDeleteContextFn *           DeleteContext;
  SpApplyControlTokenFn *           ApplyControlToken;
  SpGetUserInfoFn *         GetUserInfo;
  SpGetExtendedInformationFn *      GetExtendedInformation;
  SpQueryContextAttributesFn *      QueryContextAttributes;
  SpAddCredentialsFn *          AddCredentials;
  SpSetExtendedInformationFn *      SetExtendedInformation;
  SpQueryMetaData *         SpQueryMetaData;
  SpExchangeMetaData *          SpExchangeMetaData;
  SpGetCredUIContext *          SpGetCredUIContext;
  SpUpdateCredentials *         SpUpdateCredentials;
}SECPKG_FUNCTION_TABLE, *PSECPKG_FUNCTION_TABLE;

Appendix B: The LSA_SECPKG_FUNCTION_TABLE

The LSA_SECPKG_FUNCTION_TABLE is received by an SSP from the LSA spInitialize call. This function table provides pointers to functions that the SSP will use to interact with the LSA and client applications.

typedef struct LSA_SECPKG_FUNCTION_TABLE {
  PLSA_CREATE_LOGON_SESSION     CreateLogonSession;
  PLSA_DELETE_LOGON_SESSION     DeleteLogonSession;
  PLSA_ADD_CREDENTIAL           AddCredential;
  PLSA_GET_CREDENTIALS          GetCredentials;
  PLSA_DELETE_CREDENTIAL            DeleteCredential;
  PLSA_ALLOCATE_LSA_HEAP            AllocateLsaHeap;
  PLSA_FREE_LSA_HEAP            FreeLsaHeap;
  PLSA_ALLOCATE_CLIENT_BUFFER       AllocateClientBuffer;
  PLSA_FREE_CLIENT_BUFFER           FreeClientBuffer;
  PLSA_COPY_TO_CLIENT_BUFFER        CopyToClientBuffer;
  PLSA_COPY_FROM_CLIENT_BUFFER      CopyFromClientBuffer;
  PLSA_IMPERSONATE_CLIENT           ImpersonateClient;
  PLSA_UNLOAD_PACKAGE           UnloadPackage;
  PLSA_DUPLICATE_HANDLE         DuplicateHandle;
  PLSA_SAVE_SUPPLEMENTAL_CREDENTIALS    SaveSupplementalCredentials;
  PLSA_CREATE_THREAD            CreateThread;
  PLSA_GET_CLIENT_INFO          GetClientInfo;
  PLSA_REGISTER_NOTIFICATION        RegisterNotification;
  PLSA_CANCEL_NOTIFICATION      CancelNotification;
  PLSA_MAP_BUFFER               MapBuffer;
  PLSA_CREATE_TOKEN         CreateToken;
  PLSA_AUDIT_LOGON          AuditLogon;
  PLSA_CALL_PACKAGE         CallPackage;
  PLSA_FREE_LSA_HEAP            FreeReturnBuffer;
  PLSA_GET_CALL_INFO            GetCallInfo;
  PLSA_CALL_PACKAGEEX           CallPackageEx;
  PLSA_CREATE_SHARED_MEMORY     CreateSharedMemory;
  PLSA_ALLOCATE_SHARED_MEMORY       AllocateSharedMemory;
  PLSA_FREE_SHARED_MEMORY           FreeSharedMemory;
  PLSA_DELETE_SHARED_MEMORY     DeleteSharedMemory;
  PLSA_OPEN_SAM_USER            OpenSamUser;
  PLSA_GET_USER_CREDENTIALS     GetUserCredentials;
  PLSA_GET_USER_AUTH_DATA           GetUserAuthData;
  PLSA_CLOSE_SAM_USER           CloseSamUser;
  PLSA_CONVERT_AUTH_DATA_TO_TOKEN       ConvertAuthDataToToken;
  PLSA_CLIENT_CALLBACK          ClientCallback;
  PLSA_UPDATE_PRIMARY_CREDENTIALS       UpdateCredentials;
  PLSA_GET_AUTH_DATA_FOR_USER       GetAuthDataForUser;
  PLSA_CRACK_SINGLE_NAME            CrackSingleName;
  PLSA_AUDIT_ACCOUNT_LOGON      AuditAccountLogon;
  PLSA_CALL_PACKAGE_PASSTHROUGH     CallPackagePassthrough;
}LSA_SECPKG_FUNCTION_TABLE, *PLSA_SECPKG_FUNCTION_TABLE;