Using Side-by-side Assemblies for Kerberos for Windows

Abstract

This proposal describes a Kerberos for Windows deployment model using Microsoft Windows Side-by-side Assemblies. The goal is to produce a set of installation components that third party installers can include such that the resulting installations will be able to co-exist with other installations built from different versions of Kerberos for Windows libraries.


Table of Contents

1. Introduction

The Kerberos for Windows product has evolved since the mid-90s from a loose collection of uninstalled binaries to a set of fully packaged installers providing core libraries, an in-memory credential cache service, command line tools, single sign-on integration, and a graphical credential management tool built upon a pluggable framework permitting third parties to extend the Kerberos credentials acquisition process to obtain derivative credential types.

One of the major challenges to the distribution of Kerberos for Windows as a reliable platform upon which third party applications could rely on has been the lack of a distribution model that permits each third party application to install the version of KFW it depends upon without adversely affecting previously installed applications. To combat this problem MIT has struggled over the years to convince third party application developers to not distribute their own version of the KFW libraries and instead require their users to deploy the official distribution produced by MIT and Secure Endpoints Inc. The official version has been developed over the years such that backward compatibility is maintained.

With the introduction of Microsoft Windows XP, Microsoft provided library developers an alternative approach called Side-by-side Assemblies [1]. Side-by-side Assemblies permit each application to install and load a specific version of a library subsystem without searching the PATH environment variable. This permits multiple versions of the same library subsystem to be installed in parallel on the same system without producing cross-application interference.

This proposal outlines a deployment model based upon the use of Windows Side-by-side Assemblies. Kerberos for Windows core libraries will be packaged and distributed as a set of assemblies that applications can bind to. The assemblies will be provided in the form of Windows Installer merge modules that third parties can integrate into their installers for the purpose of redistributing the Kerberos for Windows libraries along with their applications.

Side-by-side assemblies are fully supported on Windows XP and later operating systems. They can also be deployed on Windows 2000 as shared assemblies. However, on versions of Windows prior to Windows XP, multiple different versions of a library cannot co-exist in a manner transparent to the application.

2. Assembly Organization

There are a number of components that comprise the existing Kerberos for Windows installers. A list of these components is presented in Appendix A. Of these components, the side-by-side assembly organization will only be concerned with the core libraries that are shared by third party applications.

Typically, an assembly only contains libraries. However because of its implementation and use, the Kerberos credentials cache service, krbcc32s.exe, is tightly bound to krbcc32.dll and is therefore included in the assembly.

There are two approaches to organizing the assembly. One method is to group all the binaries into a single assembly. The other is to have different assemblies for each library. Both approaches are discussed below.

2.1 Using a single assembly for all the binaries

This is the simplest method of organizing the assembly. The disadvantage with this method is that all the binaries in the assembly have to be versioned together. If there is a change in one of the binaries, a new assembly must be deployed with an larger version number containing all the binaries including the new binary.

The binaries will be organized as follows:

MIT.KerberosV.$CPU[.Debug]            ;(Assembly name)
        MIT.KerberosV.$CPU[.Debug].manifest   ;(Assembly manifest)
        krb5_32.dll / krb5_64.dll
        krb5_32.pdb / krb5_64.pdb
        comerr32.dll / comerr64.dll
        comerr32.pdb / comerr64.pdb
        gssapi32.dll / gssapi64.dll
        gssapi32.pdb / gssapi64.pdb
        k5sprt32.dll / k5sprt64.dll
        k5sprt32.pdb / k5sprt64.pdb
        krbcc32.dll / krbcc64.dll
        krbcc32s.exe / krbcc64s.exe
        krbcc32.pdb / krbcc64.pdb
        krbcc32s.pdb / krbcc64s.pdb
        xpprof32.dll / xpprof64.dll
        xpprof32.pdb / xpprof64.pdb
        wshelp32.dll / wshelp64.dll
        wshelp32.pdb / wshelp64.pdb
        

Figure 1: Example Assembly

As the first line indicates, the assemblies will tentatively be named MIT.KerberosV.$CPU[.Debug]. Assemblies containing debug or checked binaries will have a .Debug suffix. $CPU is the target architecture (x86 or IA-64).

Since an assembly can only target one architecture, 32-bit and 64-bit libraries will need to be packaged into two separate assemblies. The $CPU component of the name will differentiate between these. Although the name of the assembly does not need to differentiate based on the target architecture, doing so allows 32-bit and 64-bit assemblies to be deployed in the same location as a private assembly (See Section 3.1).

Each application is linked to a particular assembly instance via the use of an application manifest bound to the dependent executable or dynamical link library. The .manifest file is an assembly manifest [4] file that describes the contents of the assembly. A suggested manifest file is shown below for 32-bit debug libraries:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="MIT.KerberosV.x86.Debug"
                    version="3.2.2.0"
                    processorArchitecture="x86"
                    publicKeyToken="5a761611aa6ede5a" />
  <file name="comerr32.dll" hash="2ef55db0f20f83905b0392031ddbef1e7db63e69" hashalg="SHA1"></file>
  <file name="gssapi32.dll" hash="7844c963943a7bbd6d57a5936b2dd17f3efa505c" hashalg="SHA1"></file>
  <file name="k5sprt32.dll" hash="b0e7ac59ce43150018564669154d5dfe933d7151" hashalg="SHA1"></file>
  <file name="krb5_32.dll" hash="783385f697bb866c256f26439b1b4285eab44fcb" hashalg="SHA1"></file>
  <file name="krbcc32.dll" hash="76f3163415deed42010db8f5880842fdfcd85440" hashalg="SHA1"></file>
  <file name="leashw32.dll" hash="df2f3a030f26e5db7a5f6bb6c42840184a3383f2" hashalg="SHA1"></file>
  <file name="wshelp32.dll" hash="1520d062f0e17fcbb81a8a8b4c6d34106b7dc5f9" hashalg="SHA1"></file>
  <file name="xpprof32.dll" hash="6768d1ffc749f9b77a6ff97fe8ccba4df132277a" hashalg="SHA1"></file>
  <file name="krbcc32s.exe" hash="f0092316d791de2bece39828245c9b83c2dcbdb5" hashalg="SHA1"></file>
</assembly>
       

Figure 2: Example Assembly Manifest

The publicKeyToken value as well as the hash values, although based on actual binaries and a certificate issued by a self-signed test certificate authority, are for illustrative purposes only. When producing a real assembly a code signing certificate from Verisign will be required.

Such a manifest would be made public along with the Kerberos for Windows assemblies so that third party application developers can author corresponding application manifests to bind with the correct assembly. The requirements for application assemblies is discussed in Section 3.3.

2.2 Using multiple assemblies

Each library would be packaged in its own assembly. Both krbcc32.dll, krbcc32s.exe would be included in the same assembly so that the library can load the the credentials cache server using a known path.

The resulting assembly structure is:

     MIT.KerberosV.KerberosV.$CPU[.Debug]
        MIT.KerberosV.KerberosV.$CPU[.Debug].manifest
        krb5_32.dll / krb5_64.dll
        krb5_32.pdb / krb5_64.pdb

     MIT.KerberosV.ComErr32.$CPU[.Debug]
        MIT.KerberosV.ComErr32.$CPU[.Debug].manifest
        comerr32.dll / comerr64.dll
        comerr32.pdb / comerr64.pdb

     MIT.KerberosV.GSSAPI.$CPU[.Debug]
        MIT.KerberosV.GSSAPI.$CPU[.Debug].manifest
        gssapi32.dll / gssapi64.dll
        gssapi32.pdb / gssapi64.pdb

     MIT.KerberosV.K5Sprt.$CPU[.Debug]
        MIT.KerberosV.K5Sprt.$CPU[.Debug].manifest
        k5sprt32.dll / k5sprt64.dll
        k5sprt32.pdb / k5sprt64.pdb

     MIT.KerberosV.KrbCC.$CPU[.Debug]
        MIT.KerberosV.KrbCC.$CPU[.Debug].manifest
        krbcc32.dll / krbcc64.dll
        krbcc32s.exe / krbcc64s.exe
        krbcc32.pdb / krbcc64.pdb
        krbcc32s.pdb / krbcc64s.pdb

     MIT.KerberosV.XPProf.$CPU[.Debug]
        MIT.KerberosV.XPProf.$CPU[.Debug].manifest
        xpprof32.dll / xpprof64.dll
        xpprof32.pdb / xpprof64.pdb

     MIT.KerberosV.WSHelp.$CPU[.Debug]
        MIT.KerberosV.WSHelp.$CPU[.Debug].manifest
        wshelp32.dll / wshelp64.dll
        wshelp32.pdb / wshelp64.pdb

          

Figure 3: Example Assembly Structure

The KFW libraries are dependent on each other. Each library is only expected to function properly when linked with other dependent libraries from the same KFW release. Therefore, it is apropriate to treat the set of KFW libraries as a single assembly.

3. Deployment Models

3.1 Private assembly

Third party applications can use this method to install Kerberos for Windows libraries for its exclusive use as discussed in [2].

When deploying as a private assembly, the assembly files are placed in a subdirectory that has the same name as the assembly, in the corresponding application directory. The assembly will be referenced by name by an application manifest Section 3.3.

The resulting directory structure would look like the following:

  ...

  Program Files\

    MyApp\

      myapp.exe
      myapp.exe.manifest (Application manifest)

      MIT.KerberosV.$CPU[.Debug]\
        MIT.KerberosV.$CPU[.Debug].manifest
        krb5_32.dll / krb5_64.dll
        krb5_32.pdb / krb5_64.pdb
        comerr32.dll / comerr64.dll
        comerr32.pdb / comerr64.pdb
        ...

          

Figure 4: Private Assembly Installation Directory Structure

3.2 Shared assembly

If the Kerberos for Windows libraries are being installed in a shared fashion, it will be required that they be installed as a side-by-side assembly. Such a depolyment would look like the following:


  ...

  Program Files\

    MyApp\

      myapp.exe
      myapp.exe.manifest (Application manifest)

  Windows\

    WinSxS\

      Manifests\
        $versionedname.manifest (Assembly manifest)

      $versionedname\
        krb5_32.dll / krb5_64.dll
        krb5_32.pdb / krb5_64.pdb
        comerr32.dll / comerr64.dll
        comerr32.pdb / comerr64.pdb
        ...

          

Figure 5: Shared Assembly Installation Directory Structure

The $versionedname is a strong name that is generated using the assembly name, target architecture, a token value based on the certificate used to sign the assembly and the version of the assembly. It is generated when needed from assembly and application manifest data. Usage of this name is largely opaque to application developers and assembly authors.

3.3 Client Applications

Each application that links against the Kerberos for Windows libraries should declare the assembly dependency using an application manifest [5] such as the following (assuming all the Kerberos libraries are in a single assembly):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
     version="1.0.0.0"
     processorArchitecture="x86"
     name="YourCompanyName.YourDivision.YourApp"
     type="win32"
     />
  <description>Your app description here</description>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
         type="win32"
         name="MIT.KerberosV.x86.Debug"
         version="3.2.2.0"
         processorArchitecture="X86"
         publicKeyToken="5a761611aa6ede5a"
         language="*"
         />
    </dependentAssembly>
  </dependency>
</assembly>

          

This application manifest corresponds to the assembly manifest shown in Figure 2.

Figure 6: Example Application Manifest

4. Requirements and Restrictions

In order for assembly deployment to be successful, there are a number of requirements and restrictions which must be satisfied by the KFW libraries:

  1. While assemblies that are deployed as private assemblies do not need code signing, shared side-by-side assemblies are required to be signed.
  2. The assembly merge modules will not include configuration files or configuration registry settings. Installing these will be the responsibility of the application installer that incorporates the assembly.
  3. The libraries must be able to function without a shared configuration file or registry keys. Since the assemblies are designed to be redistributed along with other applications, depending on global configuration files or registry settings is not permitted.
  4. Private data structures from one version of the KFW libraries are not guaranteed to be compatible with other versions. For example objects such as the krb5_context, krb5_ccache, krb5_keytab, etc. When using assemblies it is possible for multiple versions of the Kerberos libraries to co-exist within a single process. Applications which host external DLLs (such as plug-in extensible applications) will need to ensure that data structures from one KFW version are not shared with other KFW versions. These restrictions are similar to those associated with mixing multiple C runtime library versions in the same process space. It is recommended that all private data structures be tagged with a version specific magic value so that cross-version exchange of data structures can be detected at runtime.
  5. The initialization routines of each KFW library must not interfere with the initialization routines of alternate versions of the KFW library when loaded into the same process.
  6. The base name of the assembly is MIT.KerberosV. If a third party wishes to deploy customized binaries, they should use a different base name. Applications that depend on custom binaries should explicitly depend on the correspondingly named assembly.

5. Deployment Tasks

5.1 Merge Modules

Kerberos for Windows assemblies will be packaged into Microsoft Windows Installer Merge Modules so that they can be easily integrated into existing product deployments. A single merge module can serve both as a source for a private assembly or as a source for a shared side-by-side assembly. The source code presented in Appendix B shows how such an module might be constructed.

In addition to the binaries that comprise the Kerberos for Windows libraries and their debug symbols, shared side-by-side assemblies must be digitally signed and must contain a signed catalog. The process for creating signed files and catalogs is outlined in [6].

5.1.1 Using Merge Modules for Shared Side-by-side Assembly Installation

The example merge module given in Appendix B can be used without any configuration if the Kerberos for Windows libraries are to be used as a shared side-by-side assembly.

5.1.2 Using Merge Modules for Private Assembly Installation

The FileApp configuration setting can be used to associate the assembly with a particular executable if it is to be used as a private assembly. This configuration value should be set to a string that is a key into the File table. The File table record corresponding to the key would be used as the host executable file, and the private assembly will be installed in the directory into which the executable is installed.

The following WiX code fragment shows how the merge module can be used to install the libraries as a private assembly. Any Windows Installer editing tool that supports configurable Merge Modules can be used to set the FileApp configuration value.

...

          <Directory Id="TESTAPPDIR" Name="TestApp" SourceName=".">
            <Directory Id="MM" Name="MM" LongName="MIT.KerberosV.x86.Debug">
              <Merge Id="KFWMSM" DiskId="1" Language="0" src="kfwlibs.msm">
                <ConfigurationData Name="FileApp" Value="file_testapp.exe" />
              </Merge>
            </Directory>
            <Component Id="cmp_testapp" Guid="2F7BD33D-3FC0-4C3C-9E70-DD1382D391B1">
              <File Id="file_testapp.exe" Name="testapp.exe" KeyPath="yes" DiskId="1"/>
              <File Id="file_testapp.exe.manifest" Name="testapp.exm" LongName="testapp.exe.manifest" DiskId="1" />
            </Component>
          </Directory>
...


            

Figure 7: Installing Merge Module with WiX as a Private Assembly

5.2 Releasing new versions of Kerberos for Windows

Changes that are not backwards compatible should result in the release of a new version of the assembly.

5.3 Libraries with Custom Code

If a third party needs to deploy Kerberos for Windows with modifications, they should bundle the libraries into an assembly with a different base name than MIT.KerberosV. Having a different name allows modified libraries to co-exist with MIT Kerberos for Windows on the same machine even when installed as a shared assembly.

Applications that depend on custom libraries can bind to them directly using an application manifest that refers to the custom manifest by name.

6. References

[1] Microsoft Corporation , “Isolated Applications and Side-by-side Assemblies”, <http://msdn.microsoft.com/en-us/library/aa375193(VS.85).aspx>.
[2] Microsoft Corporation , “Private Assemblies”, <http://msdn.microsoft.com/en-us/library/aa375674(VS.85).aspx>.
[3] Microsoft Corporation , “Authoring DLLs for Side-by-side assemblies”, <http://msdn.microsoft.com/en-us/library/aa374238(VS.85).aspx>.
[4] Microsoft Corporation , “Assembly Manifests”, <http://msdn.microsoft.com/en-us/library/aa374219(VS.85).aspx>.
[5] Microsoft Corporation , “Application Manifests”, <http://msdn.microsoft.com/en-us/library/aa374191(VS.85).aspx>.
[6] Microsoft Corporation , “Creating Signed Files and Catalogs”, <http://msdn.microsoft.com/en-us/library/aa375139(VS.85).aspx>.

Author's Address

Asanka HerathSecure Endpoints Inc.255 W 94TH ST PHBNew York, NY 10025USAEMail:

A. Kerberos for Windows Installation Components

The components of the current Kerberos for Windows installers are as follows. Note that the following list excludes Kerberos v4 libraries, registry keys, configuration files and other installation steps.

B. Sample WiX Source for Assembly Merge Module

The following is the Windows Installer XML (WiX) source code for a possible merge module that includes the Kerberos for Windows libraries as a single assembly.

The source code can be compiled using WiX v2. In addition to the binaries and debug symbols that comprise the Kerberos for Windows libraries an assembly manifest file (E.g.: Figure 2) and a catalog file are required. The catalog file can be created using the process outlined in [6].

<?xml version='1.0'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'>
  <Module Id='MIT.KerberosV.x86.Debug'
          Guid='B5AA69A2-87E7-4AD5-AB60-78098846E609'
          Language='0' Version='1.0.0.0'>
    <Package Id='????????-????-????-????-????????????'
             Description='Kerberos for Windows Libraries'
             Comments='Library assembly'
             Manufacturer='MIT' InstallerVersion='200' Compressed='yes' />

    <Directory Id='TARGETDIR' Name='SourceDir'>
      <Directory Id='ModuleDir' Name='.' FileSource=".\">
        <Component Id='cmp_KrbVAssembly' Guid='065094BA-A0F3-432A-AD7D-A96900298602'>
          <File Id="file_comerr32.dll" Name="comerr32.dll" Vital="yes" />
          <File Id="file_comerr32.pdb" Name="comerr32.pdb" Vital="yes" />
          <File Id="file_gssapi32.dll" Name="gssapi32.dll" Vital="yes" />
          <File Id="file_gssapi32.pdb" Name="gssapi32.pdb" Vital="yes" />
          <File Id="file_k5sprt32.dll" Name="k5sprt32.dll" Vital="yes" />
          <File Id="file_k5sprt32.pdb" Name="k5sprt32.pdb" Vital="yes" />
          <File Id="file_krb5_32.dll" Name="krb5_32.dll" Vital="yes"
                KeyPath="yes" Assembly="win32"
                AssemblyManifest="file_MIT.KerberosV.x86.Debug.manifest"/>
          <File Id="file_krb5_32.pdb" Name="krb5_32.pdb" Vital="yes" />
          <File Id="file_krbcc32.dll" Name="krbcc32.dll" Vital="yes" />
          <File Id="file_krbcc32.pdb" Name="krbcc32.pdb" Vital="yes" />
          <File Id="file_krbcc32s.exe" Name="krbcc32s.exe" Vital="yes" />
          <File Id="file_krbcc32s.pdb" Name="krbcc32s.pdb" Vital="yes" />
          <File Id="file_leashw32.dll" Name="leashw32.dll" Vital="yes" />
          <File Id="file_leashw32.pdb" Name="leashw32.pdb" Vital="yes" />
          <File Id="file_MIT.KerberosV.x86.Debug.cat"
                Name="KrbV.cat" LongName="MIT.KerberosV.x86.Debug.cat"
                Vital="yes" />
          <File Id="file_MIT.KerberosV.x86.Debug.manifest"
                Name="KrbV.man" LongName="MIT.KerberosV.x86.Debug.manifest"
                Vital="yes" />
          <File Id="file_wshelp32.dll" Name="wshelp32.dll" Vital="yes" />
          <File Id="file_wshelp32.pdb" Name="wshelp32.pdb" Vital="yes" />
          <File Id="file_xpprof32.dll" Name="xpprof32.dll" Vital="yes" />
          <File Id="file_xpprof32.pdb" Name="xpprof32.pdb" Vital="yes" />
        </Component>
      </Directory>
    </Directory>

    <Configuration Name="FileApp" Format="Text"
                   DisplayName="File_Application value"
                   NonNullable="no"
                   Description="File identifier for host executable if Kerberos for Windows is to be used as private assembly.  If this value is NULL, then the assembly will be installed as a side-by-side assembly." />
    <Substitution Table="MsiAssembly" Row="cmp_KrbVAssembly"
                  Column="File_Application" Value="[=FileApp]" />
  </Module>
</Wix>

        

Figure 8: Sample WiX Source for Assembly Merge Module