Certificates

Although we've focused so far on signing an assembly with a .NET strong name, there are of course two ways of signing an assembly. The key generated by the sn.exe utility and indicated by the AssemblyKeyFile attribute is stored in a .NET-specific format, and is used to sign an individual assembly (or possibly all the assemblies in an application or library). It deals specifically with the CLR-specific information. On the other hand, there has for many years been separate support on Windows for signing any PE file, using Microsoft's Authenticode technology (which we'll cover soon). The purpose of the two signatures is different. While sn-generated keys are normally used to identify assemblies or applications, Authenticode signatures are used to identify the publisher - the company that produced the assembly. Although the basic public-private key principles and algorithms are the same, the actual file formats used for the keys are different, and different command-line utilities are used to manipulate the keys. Another difference is that Authenticode signatures are designed to provide protection at the time when you download or install an application, by providing confirmation that the company claimed to have written the software did indeed write it (and as we'll see soon, they provide a far stronger guarantee of this than .NET strong names). The support in the CLR for strong names ensures that a strong name is checked every time an assembly is loaded.

There's nothing to stop you from signing an assembly in both ways - and for security purposes that is normally a good idea. This means you'll end up with an assembly that looks a bit like this:

click to expand

So what exactly is the problem with only using a strong name? Well, if a file has been signed, then that means you can trust that file's integrity to the same extent that you trust the private key it has been signed with. Are private keys trustworthy? The problem at the moment is that I can easily generate a private key just by running sn or a similar utility to create a private key. What is there to stop me, as a freelance programmer working from home, from creating a private key, then claiming that I am Microsoft Corporation, and here's my Microsoft Corporation private key to prove it? Well, OK, claiming to be a huge company like Microsoft might be stretching it a bit, but you get the point. You might have established that a piece of software was signed with a certain private key, but you still need to be satisfied that that private key really does belong to the person or company indicated. That's where certificates and certification authorities (CAs) come in. Let's look at certificates first.

Although certificates and CAs are used to verify all sorts of communications, including e-mails, and connecting to web sites, from now on we'll concentrate exclusively on applying cryptography and certificates for downloading files - simply because that's the area that's most relevant to .NET assemblies. The same basic principles apply to other areas though.

What is a Certificate?

A certificate is simply a file that contains a public key along with information about who that key belongs to. Although the concept is so simple, certificates are so important that a couple of industry-standard specifications for certificates exist. The one normally used on Windows is the X.509 certificate, which is stored in a file with extension .cer. You may also encounter .p7b files, which store another type of certificate, known as PKCS #7. The fields included in an X.509 certificate include the algorithm used for the key, the name of the owner, the dates between which the certificate is valid, the public key itself, and any additional information the issuer chooses to add, such as a contact e-mail address or URL.

Our problem can now be restated as follows: what is there to stop me from creating an X.509 certificate on my computer, putting "Microsoft Corp" in the "owner" field, then passing it around the Internet? Well, the answer is "nothing" - you or I could indeed do that in principle (though it wouldn't be legal in most countries). The problem (or should I say the solution) is that no one would trust the certificate because it hadn't been issued by a recognized certification authority (apart from the fact that Microsoft would probably take an interest in the matter very quickly).

Certification Authorities

There are quite a number of certification authorities around now. Verisign is the most well known, but there are others, such as Thawte, GlobalSign, EnTrust, and PGP (Pretty Good Privacy). These organizations earn a living by checking your identity and vouching for certificates that you issue.

The technical details of what happens are fairly complex, but we'll go through the rough principles. If you decide that you need a private key and you want to be certified by a CA, then you will apply to that CA and pay the relevant fee. The CA will then spend some time performing various background checks on you or on your organization. The details of the checks vary depending on what country you are applying from, which CA you apply to, and what fee you pay the CA - the higher the fee, the more checks will be carried out, and the better your certificate will be (because the certificate you get will come categorized according to the level of checks made). They can range from a simple check that you are contactable at your e-mail address up to checks on your physical address, tax returns, and company listings. Once the CA has satisfied itself of who you are, it will issue the certificate. This will normally be done through your browser, over an HTTPS Internet connection, and depends on some in-built support from your browser (which is provided by both Internet Explorer and Netscape Communicator). Your browser will generate a private key, work out the corresponding public key, and send it securely to the CA web server. Notice how this works. The private key is generated locally on your machine and stays there. It is not generated by the CA - if the CA did that then it would have to send the key over the wire to you, which would ruin the whole point of private keys! The CA never finds out what your private key is, but it does store the corresponding public key.

How does that help you to sign your software? Well, as soon as your web browser has sent your public key to the CA, the CA will use this key to generate a certificate. Then the CA will sign the certificate - with its private key, in just the same way as you sign PE files, and will send the signed certificate back to you. You now have a certificate that details your public key, as well as various fields that say who you are, and which has been signed by the CA.

Now, suppose that later on, you have reached the point at which you have written some code, you have generated a hash of your PE file, and you want to sign the file. So you encrypt the file with your private key. Now, if you weren't using a certificate you'd place your public key in the file. However, with a certificate, you can do something better: you can put your certificate in the file.

Now your code gets distributed. At some point someone downloads the code or otherwise tries to run it. Windows sees that the PE file contains a certificate, so one of the first things it does is process the certificate in order to verify file authenticity. Windows will need to decrypt the signature. Now recall that the certificate has been signed with the CA's private key, which means that Windows needs to use the CA's public key to decrypt the signature. At this point the great bonus of signatures comes in to play: there are certain CAs called root CAs that Microsoft knows about and trusts. And Microsoft has hard-coded knowledge of the certificates that belong to those CA's into Windows (they are stored by Internet Explorer). Thus when Windows decrypts a certificate that has been signed by a root CA, it does so using one of these hard-coded public keys. Successfully decrypting the certificate in this way proves that it was issued by a root CA and is therefore trustworthy. The point is that because the public keys of the root CA's are hard-coded into Windows, there can be no doubt about the authenticity of the signatures.

Once this check has been made, Windows can verify that your PE file is genuine and has not been tampered with. Windows can decrypt the hash of the PE file using your public key, yielding the raw hash value. Windows knows that all the information it read out of the certificate is correct and trustworthy - and that information includes your public key needed to decrypt the hash of the PE file, as well as the details of who you are. Now Windows can perform its own independent calculation of the hash value from the file contents - and if it matches the decrypted value then the software has been authenticated.

One of the great things about certificates is that they are recursive. You don't have to get your certificates signed directly by a root CA. There may be another, smaller, CA, which is not recognized as a root but which has arranged for its certificates to be signed by a larger CA. The whole process can go on until a root CA signs the certificate. As long as there is a root certificate at the end of the chain, it doesn't matter how long the chain is. Windows will still be able to confirm whether your PE file is signed and therefore trustworthy.

What happens if the file is not authenticated depends on your policies. The most common situation in which you encounter the use of certificates is when you download an ActiveX control from an Internet site. Windows Explorer will check whether the control has been signed. If IE is running at the medium security level and this is an untrusted site, then you'll get a dialog like this if the control has been signed with a recognized root public key:

click to expand

And a dialog like this if it doesn't have a key (there's a similar but slightly different dialog that appears if the application has been signed by an untrusted key - that is, a key that can't be traced back to a CA that Windows knows about):

click to expand

Personally, I don't think these dialogs have been that well designed. If you don't understand the process of generating certificates and the significance of some software having been signed (and let's face it, that'll be about 99.9% of Internet users) then the first of these dialogs looks more like a warning that something might be wrong - when in fact it's your reassurance that the software was definitely written by the company indicated on the dialog box. The second dialog doesn't look that different from the first, but the underlying meaning is very different: there's no guarantee that you can trust this software.

Note that most of the discussion in this section has focused on the general principles of how certification works. The particular implementation of these principles on Windows - the software on your computer that supports checking of certificates - is known as Authenticode.

You can see the trusted roots on your machine by running an application called certmgr. (Just type in certmgr at the VS.NET command prompt.) You'll get a dialog box with a large property sheet on it. Select the Trusted Root Certification Authorities tab and you'll see the list:

click to expand

Can Certification Fail?

Now we've seen how the certification system works, we'll consider how secure the system is. Are there any weak points that make it possible for a hacker to break in and put some malicious software on your computer?

Can Malicious Code be Certified?

Could a malicious party get themselves certified then use their certificate to distribute malicious code? If - someone did, it wouldn't take long before one of their victims figured out which piece of code was interfering with their system and reported the fact to the relevant CA. The CA could then test the code to confirm the problem, revoke the certificate, and report the matter to the authorities. Even better, because the code is digitally signed, the non-repudiation principle cuts in. The malicious party can't deny having written the code because proof is there in the form of the digital signature. Enter lawyers, courts, and (depending on the local laws) a possible jail sentence.

Lost or Stolen Private Key

Private keys are supposed to be kept absolutely secure, but it's possible that the unthinkable might happen - some organization might lose its private key (or worse - have it stolen). This means that whoever stole the key can write code purporting to be from that organization. However, certification will protect against this. As soon as the loss is discovered, the organization can report the loss to the CA, which will expire the certificate and issue a new one. Although we won't go into the details of the technology, I will say that in principle it is still possible to distinguish code that has been signed and timestamped before the certificate expired, and which therefore is still trustworthy.

User Errors and Trojans

In practice, user errors are the means by which most problems occur. Using the various tools concerning security and cryptography require quite a good understanding of cryptography and Authenticode in order to use them properly - so it's not inconceivable that administrators and users can make mistakes in setting up their policies and trusted keys. Add to that the viruses and Trojans that users open in their e-mails for example. A virus that trashes your system tends to get noticed instantly, but there are also Trojans around which don't have any obvious visible effect. They simply make subtle changes to the security settings on your computer to make it easier for a hacker to break in later on - and that might theoretically include adding certificates to your trusted root list. Obviously, the only real protection against this is to ensure you have up-to-date virus protection, and don't open suspicious e-mail attachments. But as an experienced programmer, you already take those precautions, don't you...

Then of course there are the millions of Internet users who happily download and run PE files that have not been certified at all. There's not really a lot that certification can do about that!

The Windows Cryptography Model

Windows does have fairly sophisticated cryptography features, which implement all the principles we've discussed in this chapter, and which allows you to do things like generate public/private key pairs, or symmetric keys, encrypt and decrypt data, sign files or even create X.509 certificates (though obviously, any certificates you create manually won't be backed up by any certification authority, and so won't be regarded as trustworthy outside your organization).

The Windows cryptography SDK exposes command-line utilities and an unmanaged API known as the CryptoAPI. To this the .NET Framework adds the classes in the System.Security.Cryptography and related namespaces. The underlying architecture is based on programs known as cryptographic service providers (CSPs) - these are the programs that actually implement the cryptographic algorithms. The CryptoAPI invokes CSPs, as shown in the diagram:

click to expand

The situation is quite analogous to the architecture of GDI+ (or GDI or DirectX for that matter). Recall that when you use GDI+ to perform drawing, GDI+ will communicate with whatever device drivers are available on your output device to get the drawing done. Similarly, the CryptoAPI is implemented as a set of Windows API functions that are internally implemented to communicate with a cryptographic service provider that actually performs the task. Microsoft has supplied a base CSP, which comes with Windows NT/2000/XP Professional and above as standard. If you don't explicitly change the CSP, that will be the one that is called by default when you invoke any CryptoAPI function. However, it is perfectly permissible for third parties to register their own CSPs. Before you ask, though, it's not possible for just anyone to write and install a CSP. If that were possible then you could imagine the hackers eagerly queuing up to install rogue CSPs that do bad things such as pass on private keys!) Any CSPs need to be signed by Microsoft before the CryptoAPI will recognize them. And clearly Microsoft will only sign a CSP if it is satisfied as to the integrity of the CSP software, and if the CSP software satisfies all the various legal requirements.

Creating a Certificate

We are now going to demonstrate how to attach a certificate to an assembly. This means signing the assembly using various command-line tools that use the default CSP to create a certificate and add the certificate to the list of trusted roots maintained by your computer. We then use a tool called SignCode.exe, which actually signs the code with the certificate.

Do bear in mind that signing with SignCode is not the same as signing with an sn-created key. As mentioned earlier, the two processes are similar but independent of each other. Signing using SignCode is intended to verify the publisher rather than the assembly, and does not give the assembly a strong name. In this example we won't be attaching a .NET private key to the assembly we create, but the procedure is identical for an assembly that has a strong name.

First, for this sample, we need the program that will be signed. We'll go for another simple Ariite, Wurld! application (a dialect-specific variation of Hello, World!), although this program is a Windows forms rather than a console application. Here's the code for it:

 using System; using System.Windows.Forms; using System.Drawing; namespace Wrox.AdvDotNet.SignedForm {    public class EntryPoint    {       static void Main()       {          Form form = new Form();          form.Text = "Ariite, Wurld!";          form.Size = new Size(200,200);          Application.Run(form);       }    } } 

I've kept the code as simple as possible because it's not the code we're interested in here - it's the signing procedure.

In order to create a certificate we need a batch file. Here it is:

 MakeCert -sv TestRoot.pvk -r -n "CN=Simons Test Root" TestRoot.cer Cert2SPC TestRoot.cer TestRoot.spc CertMgr -add -c TestRoot.cer -s root 

There's quite a lot going on here so we'll go over it carefully. And you'll also find that when you run this code you'll get a few dialog boxes asking you for passwords.

The first command, MakeCert, is the command-line utility that creates a certificate - creating an appropriate public-private key pair in the process.

 MakeCert -sv TestRoot.pvk -r -n "CN=Simons Test Root" TestRoot.cer 

This command will place the certificate in a file called TestRoot.cer. The certificate file contains only the public key, so we need to store the private key somewhere else. The -sv option indicates the file in which the private key should be stored. The key is actually stored in an encrypted, password-protected form, and MakeCert will pop up a dialog asking you to choose the password. This password will not be stored anywhere so you'll need to remember it. The -r option indicates that this certificate will be self-signed. That basically means it's not going to be signed by any CA - it can exist at the end of any chain of certificates. -n gives the name by which the certificate will be known, in LDAP format.

Note that if you create a certificate in this way, then under the terms of the Windows license, you are not permitted to use the certificate to publicly distribute software. You may use it only for testing purposes within an application. For certifying software for shipping, you must omit this step and obtain a .cer file from a certification authority instead.

Cert2SPC simply copies the .cer file into a different file format that is specifically intended for signing code (as opposed to authenticating a web site, for example).

CertMgr is more interesting. This is the command that actually manipulates the store of registered certificates. We've already encountered the CertMgr utility in this chapter, when we showed that if you run it without any parameters, it pops up a form that allows you to manipulate the store from a user interface. Running it with parameters causes it simply to perform the requested task and exit, although you still get a dialog box asking you to confirm the adding of the key to the store. I guess Microsoft decided that adding trusted keys was such a potentially dangerous operation that they put this in as a safeguard.

click to expand

Incidentally, MakeCert works the same way: you can invoke MakeCert without any parameters, in which case you'll get a form that guides you through a wizard to make the certificate. In our case we pass CertMgr the options -add, which tells it to add the specified item to the store, -c, which tells it that it is a certificate file we want to add, and -s root, which tells it to make the certificate a trusted root. This is important: if you don't do that, then the following call to SignCode.exe will sign the file, but Windows won't recognize the signed file as in any way trusted because it won't be able to link the certificate to a trusted root.

Now that we have created and installed the certificate, we are ready to build and sign the executable. Here's the batch file to do that:

 csc AriiteWurld.cs SignCode -v TestRoot.pvk -spc TestRoot.spc AriiteWurld.exe 

SignCode.exe is used to actually sign the executable with the certificate. Notice that we need to pass it the certificate itself (in the form of a .spc file), and also the private key. Because the TestRoot.pvk file is password-protected, you'll be prompted for the password when this instruction is executed. Just as with the previous sample, you won't normally want developers to have access to the .pvk file, so the process of signing the code will be performed by some trusted individual, but for this sample we won't worry about that. In the case of digital certificates, there is no facility to delay-sign an assembly. It's not needed since the certificate does not form any part of the assembly's identity. The above code will sign but won't timestamp the assembly. To timestamp it you need to supply the option -t, and give the path of a DLL capable of performing the timestamping. There is one provided by Verisign, so the syntax would look like this:

 signcode -v PrivKey.pvk -spc TestRoot.cer -t http://timestamp.verisign.com/scripts/timstamp.dll ariitewurld.exe 

If you explore the MSDN documentation for the .NET command-line utilities, you'll find MakeCert, SignCode, and related tools listed as .NET utilities. Don't be fooled by this - these utilities are part of the cryptography SDK and have been around since the days of IE4. They will work equally well on any PE file, whether or not it is an assembly.

Now we've signed the assembly - but what difference is it going to make? One way to tell is to run the utility, ChkTrust on it. (Just type in ChkTrust <filename> at the command prompt). ChkTrust will examine the certificate and display the appropriate message box warning you about its contents - the same message box that is displayed in Windows Explorer. In our case, we get this:

click to expand

It's also possible to use a tool called SecUtil to extract the public key from the file:

click to expand

SecUtil will only retrieve the key if the file has a valid Authenticode signature, which can be traced to a trusted root - otherwise it'll display an error message. Thus SecUtil not only provides one way of retrieving the public key if you need it for any reason, but also serves as a way to check that the signing process was successful. SecUtil by the way is CLR-aware. Instead of typing in -x (=retrieve X.509 key) you can pass it the option -s, in which case it'll retrieve the strong name for the assembly, if it exists.

However, the final proof of the pudding is whether the CLR's code-based security mechanism will recognize the certificate. To check this you should move the AriiteWurld.exe file to some location off the remote machine, from which it would not normally be trusted to run. Placing it on the Internet is ideal. Then try downloading it from Internet Explorer and see the result - a security policy exception dialog. Now use your favorite tool - either caspol or mscorcfg.msc which we saw in Chapter 4, to add a new code group that gives full trust to code that is signed with your newly created certificate. Personally, I find this easier using the mscorcfg.msc snap-in, since you can click to add a new code group, then select a membership condition based on publisher for the new group, and you get a dialog box asking you to browse down to the .cer file that contains the certificate. This means you don't have to manually copy and paste the public key - mscorcfg.msc will read it from the certificate file. In this screenshot, the appropriate button has the focus. Clicking it will bring up the standard File Open dialog to allow you to search for the file:

click to expand

With this code group added, you should find that AriiteWurld.exe will now successfully download and execute, even from an untrusted location.

Reading a Certificate Programmatically

We will finish off by presenting a very short example that complements the previous sample. Where we've just created an X509 certificate and used it to sign an application, we'll now write a short example that can read the certificate and display information about it. The example uses the X509Certificate class.

The code looks like this:

 static void Main() {    string filePath;    OpenFileDialog dlg = new OpenFileDialog();    if (dlg.ShowDialog() != DialogResult.OK)       return;    filePath = dlg.FileName;    Console.WriteLine(filePath);    X509Certificate cert = X509Certificate.CreateFromCertFile(filePath);    Console.WriteLine("Name:\t\t" + cert.GetName());    Console.WriteLine("Algorithm:\t" + cert.GetKeyAlgorithm());    Console.WriteLine("Valid from:\t" + cert.GetEffectiveDateString());    Console.WriteLine("Valid to:\t" + cert.GetExpirationDateString());    Console.WriteLine("Issuer:\t\t" + cert.GetIssuerName()); } 

The first part of the code opens a standard Open File dialog to allow the user to select the .cer file to examine. For simplicity's sake, there is no error checking here - we trust the user to pick a file of the appropriate type. Next we instantiate an X509Certificate instance based on the file. The X509Certificate class is in the System.Security.Cryptography.X509Certificates namespace. It's defined in mscorlib.dll, in common with all the cryptography classes, so you don't have any extra assemblies to link in. You can use the class to read an existing certificate, but you can't use it to create one (that doesn't appear to be possible with the cryptography classes - to do that you need to fall back on native APIs - but then unless you happen to be a CA, you shouldn't normally want to create certificates anyway).

Finally we simply use various methods on the certificate to display various fields. We don't retrieve the public key in this example (it's available as a string through the GetPublicKeyString() method) because I don't really want to display another public key screenshot - public keys are too big and don't make especially exciting reading... Anyway, the output when I run the DisplayCertificate sample and select the certificate I created in the last sample looks like this:

 E:\Advanced dotNET\13_Cryptography\Edits\Samples\CreateCertificate\TestRoot.cer Name:           CN=Simons Test Root Algorithm:      1.2.840.113549.1.1.1 Valid from:     03/11/2002 08:01:25 Valid to:       31/12/2039 15:59:59 Issuer:         CN=Simons Test Root 

It's interesting to note that the X509Certificate methods such as GetName() and GetIssuerName() that we use here would normally have been expected to have been implemented as properties (since they return non-volatile property-like items of information without modifying the class instance). I've already noted a few minor eccentricities in the design of the System.Cryptography classes earlier in the chapter this makes me suspect that either these classes were designed in a hurry, or there was some lack of communication between teams at Microsoft at some point. I should stress, though, that these problems appear to be confined to the interface design. I've not noticed any issues with the underlying implementations.



Advanced  .NET Programming
Advanced .NET Programming
ISBN: 1861006292
EAN: 2147483647
Year: 2002
Pages: 124

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net