GAC Nitty Gritty, Part 1

Intro

Global Assembly Cache, is one of the most important scapes of .NET framework, however there are so many tips and tricks, and guidelines that you should be aware of, unfortunately most of developers when asked about GAC, they barely would tell what it stands for, GAC is a major scape of .NET architecture, and I believe that understanding what .NET is so important as I have seen so many people around arguing about .NET inner workings and how insignificant to know, I believe that if you know how .NET is doing the magic for you, this would help you so much, everyone can write code, but how many people know the architecture of .NET, not so many people, however in this post I will try to deliver my knowledge and my experience with GAC, I have read so many articles, blog posts, forums discussions, and MSDN documentation, and at the end of this post I will mentioned related readings so you can follow and get more knowledge about GAC.

GAC, Why ?

"GAC is built specifically to be a machine-wide repository for system and custom assemblies, with support for versioning", this is the ultimate objective for GAC, one location for global assemblies, so each and every .NET assembly can access the global assemblies stored in the GAC, plus you can have versioned assembly inside the GAC, and this is how .NET solved the DLL Hell classical problem , so inside the GAC you can have more than one assembly with the same name but with different versions, and in the next lines we will explain throughly how .NET achieves versioning for GAC assemblies, so to recap; GAC is a repository in which we keep global versioned assemblies!, one more thing is worth mentioning is that default machine polity grants "full trust" to all assemblies installed into the GAC, and this is a very cool feature I remember that I developed a custom ASP.NET 2.0 WebPart that I wanted to use at Sharepoint Server 2007, when I was adding the WebPart assembly in the default web application bin folder, I had to write policy file to grant my assembly permission to be used from inside MOSS 2007, whilst instaling the assembly into the GAC, it just works and you don't care about any code access security for your assembly.

GAC, How ?

To get your assembly installed into the GAC, you have to digitally sign it by generating a strong name key by launching Visual Studio 2005 Command Prompt, enter "sn -k filename.snk", this writes the file into the current location from which you are running the command, and if you build a class library project from VS.NET you can right click the project from solution explorer and click Properties, select Signing, check the Sign the assembly, from the dropdown list you can select either to create a new strong name key through VS.NET or browse to the one you've created before using the VS 2005 command prompt.

SNK, Why and How ?

You might wonder about the need for generating the strong name key file and assigning it to the assembly whilst building it, at the first place any assembly to be placed into the GAC, it has to be built with snk file, but note that it's always good to sign your assemblies regardless of being installed into the GAC, so even if you don't intend to install your assembly into the GAC; you can still sign it using a strong name key, snk gives a unique indentity to your assembly just like the GUID was a unique identifier for COM objects, also when you digitally sign your assemblies using strong name key is preventing spoofing or tampering your assemblies, that may be hacked by any malicious source, for example if you have BizTalk Server 2006 installed on your machine, check your GAC at %windir%\assembly, you will find out that almost all BizTalk Server assemblies hold public key token ( more about this later ), as 31bf3856ad364e35, this tells the .NET CLR of your machine that these assemblies are coming from the source they are coming from ( I know it's somehow difficult to grasp ), now we'll examine the contents of one digitally signed assembly strong name; the strong name of one assembly consists of the following :

  • Public Key Token: also know as the public key ( example: 31bf3856ad364e35 ).
  • Assembly Name: it's the assembly name after suppressing ".dll", ( example: Microsoft.BizTalk.Messaging).
  • Assembly version: standard pattern is, Major.Minor.Build.Revision, ( example: 3.0.1.0 ).
  • Culture : culture identity value, ( example : Neutral ).
  • Digital Signature: this is hash value, more about that later, encrypted using the private key.
The process of the signing and verification can be depicted using the following process diagram:



Compilation Time
  1. When you create snk file using the SNK.exe, the public and private keys are written into the file, and one more thing to notice, that you can protect your snk file using a password.
  2. After binding your assembly with the strong name key, and when you compile your assembly, the compiler generates a "Hash Value", using the assembly IL code and meta data as an input and the algorithm used for hashing is SHA-1 Hash algorithm.
  3. Compiler reads the private key from the snk file, and takes the hash value generated in step 2 as an input for encryption, compiler uses RSA Public Key Algorithm to generate the digital signature that will be shipped with the assembly, while the private key is never included in the assembly metadata, it is always kept in a secure place.

Run Time

  1. Whenever the CLR loads an assembly that's digitally signed, regardless of being in the GAC or not, CLR reads the digital signature and tries to verify it, then it compares the digital signature included in the assembly, to the one that it evaluates at runtime if they are equivalent the CLR continues loading the assembly, otherwise the assembly is not loaded, first step CLR carries out is to generate a hash value from assembly contents, IL + metadata, this is done using the same hashing algorithm used by the compiler it's SHA-1.
  2. CLR decrypts original hash using the public token/key and same encryption algorithm used before, RSA Public Key algorithm, remember the digital signature is just an encrypted hash value using the private key.
  3. CL compares original hash value ( from step 2 ) and current hash value ( from step 1 ), if they are the same, CLR loads the assembly, otherwise it's not loading the assembly, and if the hash values are not equal, that means the assembly contents have been changed or they are not signed using the correct snk, that's coming from specific publisher/source.
Note that the assembly that is strongly named undergoes the runtime CLR signature verification every time it is getting called by another assembly , on the other hands this process is done only once for GAC assemblies while installing the assembly into the GAC, and then the CLR doesn't check it every time it's getting called, considering it's coming from a trusted source, because you wouldn't install an assembly into the GAC if you don't have administrative rights on the target machine.

Inside GAC

GAC is located at %windir%\assembly if you try to browse to this location, windows shell extension will load and show the contents of the GAC, the shell is named SHFusion.dll, and it's worth mentioning that the first codename for GAC versioning was Fusion, however after you browse to the GAC location you get the assemblies listed as shown below:


I will stop at this point and the next post I will go deeper into the GAC, and explain how the .NET framework is achieving the versioning behind the scenes.

Disclaimer: In part 2, I will gather and mention references and related readings.

Labels: