In an effort to learn how to sign PowerShell scripts and configuration files, you have searched the Internet, read several blogs about code signing, reviewed the PowerShell documentation, and even browsed through some PowerShell books. Yet the more you read about code signing, the more confused you are. Finally, in frustration, you open your PowerShell console and enter the following command:
set-executionpolicy unrestricted
Before you enter this command, remember what you learned about execution policies in Chapter 3, "PowerShell: A More In-Depth Look." Using the Unrestricted setting negates an important security layer that was designed to prevent malicious code from running on your system. Code signing is another essential component of PowerShell security, but many people believe it's too complicated to learn and set their execution policies to Unrestricted to avoid having to use it. In response to an entry on script signing at Scott Hanselman's blog (http://www.hanselman.com/blog), one person commented that "Handling code signing certificates is way over the head of most users, including average developers and admins." This statement indicates a real need that should be addressed—hence this chapter devoted to code signing. Code signing seems complicated on the surface, but with some clear instructions, the process is easy to understand. Scripters, developers, and administrators should be familiar with it as an important part of their overall security efforts.
What Is Code Signing?
In short, code signing is the process of digitally signing scripts, executables, DLLs, and so forth to establish a level of trust for the code. The trust granted to digitally signed code is based on two assumptions. One, a signed piece of code ensures that the code hasn't been altered or corrupted since being signed. Two, the digital signature serves to prove the identity of the code's author, which helps you determine whether the code is safe for execution.
These two assumptions are a way to ensure the integrity and authenticity of code. However, these assumptions alone are no guarantee that signed code is safe to run. For these two assumptions to be considered valid, you need the digital signature and the infrastructure that establishes a mechanism for identifying the digital signature's originator.
A digital signature is based on public key cryptography, which has algorithms used for encryption and decryption. These algorithms generate a key pair consisting of a private key and a public key. The private key is kept secret so that only the owner has access to it, but the public key can be distributed to other entities through some form of secure interaction. Depending on the type of interaction, one key is used to lock (encrypt) the communication, and the other key is used unlock (decrypt) the communication. In digital signatures, the private key is used to generate a signature, and the public key is used to validate the generated signature. The process is as follows:
A one-way hash of the content (documents, code, and so forth) being signed is generated by using a cryptographic digest.
The hash is then encrypted with the private key, resulting in the digital signature.
Next, the content is transmitted to the recipient.
The recipient then creates another one-way hash of the content and decrypts the hash by using the sender's public key.
Finally, the recipient compares the two hashes. If both hashes are the same, the digital signature is valid and the content hasn't been modified.
A one-way hash (also known as a message digest, fingerprint, or compression function) is a cryptographic algorithm that turns data into a fixed-length binary sequence. The term one-way comes from the fact that it is difficult to derive the original data from the resulting sequence.
To associate an entity, such as an organization, a person, or a computer, with a digital signature, a digital certificate is used. A digital certificate consists of the public key and identifying information about the key pair owner. To ensure a digital certificate's integrity, it's also digitally signed. A digital certificate can be signed by its owner or a trustworthy third party called a certificate authority (CA).
The act of associating code with the entity that created and published it removes the anonymity of running code. Furthermore, associating a digital signature with a code-signing certificate is much like using a brand name to establish trust and reliability. Armed with this information, users of PowerShell scripts and configuration files can make informed decisions about running a script or loading a configuration file. This, in a nutshell, is why code signing is an important aspect of the PowerShell security framework.
Obtaining a Code-Signing Certificate
There are two methods for obtaining a code-signing certificate: generating self-signed certificates and using a CA from a valid public key infrastructure (PKI).
Generating a self-signed certificate for signing your PowerShell scripts and configuration files is simpler and quicker and has the advantage of not costing anything. However, no independent third party verifies the certificate's authenticity, so it doesn't have the same level of trust that's expected from code signing. As a result, no other entity would trust your certificate by default. To distribute your PowerShell script or configuration file to other machines, your certificate would have to be added as a trusted root CA and a trusted publisher.
Although changing what an entity trusts is possible, there are two problems. One, entities outside your sphere of control might not choose to trust your certificate because there's no independent method for verifying who you are. Two, if the private key associated with your self-signed certificate becomes compromised or invalid, there's no way to manage your certificate's validity on other entities. Given these problems, limiting the use of self-signed certificates to a local machine or for testing purposes is recommended.
If you plan to digitally sign your scripts and configuration files so that they can be used in an enterprise or even the public realm, you should consider the second method of obtaining a code-signing certificate: a CA from a valid PKI. A valid PKI can mean a well-known and trusted commercial organization, such as http://www.globalsign.net, http://www.thawte.com, or http://www.verisign.com, or an internal PKI owned and operated by your organization. Obtaining a code-signing certificate from an external PKI can be quick and easy, as long as you keep a few caveats in mind.
First, a certificate must be purchased from the owner of the external PKI. Second, because you're purchasing the certificate from an outside entity, you're placing a lot of trust in the organization's integrity. For these reasons, code-signing certificates from commercial PKIs should be limited to certificates used to sign scripts and configuration files for public distribution.
Therefore, an internal PKI should be used for scripts and configuration files not meant for public consumption. Keep in mind that deploying and managing an internal PKI takes planning, effort, and money (Hardware Security Modules (HSMs), security consultants, and so forth can be expensive). Most organizations tend to shy away from the effort required to set up a PKI. Instead, they bring up CAs ad hoc, purchase certificates from commercial PKIs, or ignore PKI requirements. A commercial PKI might not provide the level of trust your organization needs, and the ad hoc approach isn't recommended because it reduces trust of certificates generated by rogue CAs, which are CAs that have a low level of assurance around their integrity. Having no valid PKI infrastructure could make internal distribution of digitally signed files difficult. Last, organizations that ignore PKI requirements illustrate another drawback of using an internal PKI: time.
If there's no PKI in your organization, obtaining a code-signing certificate might take an extended period of time. PKIs do not materialize overnight. If you have identified a PKI requirement for your scripts, there are probably additional PKI requirements in your organization. These requirements will need to be identified and considered before a PKI is deployed. Trying to drive a PKI deployment around your needs alone isn't the best approach for an infrastructure service that needs to meet the needs of an entire organization. After you have presented the PKI requirement to your organization, you might have to wait for the services to be provided. However, after the PKI is in place, you can obtain code-signing certificates knowing that the infrastructure fully supports the distribution of your signed PowerShell scripts and configuration files.
Method One: Self-Signed Certificate
This method of creating a self-signed certificate is based on using the makecert utility, which is part of the .NET Framework Software Development Kit (SDK). Follow these steps:
Download the latest Microsoft .NET Framework SDK from http://msdn2.microsoft.com/en-us/netframework/aa731542.aspx. At the time of this writing, the current .NET Framework SDK version is 2.0.
Install the SDK on the machine where you want to generate the self-signed certificate.
Locate the makecert utility on your system. The default location is C:\ Program Files\ Microsoft Visual Studio 8\ SDK\ v2.0\ Bin.
Open up a cmd command prompt and change the working directory to the location of the makecert utility using the cd command.
Create a self-signed certificate by using the following command:
makecert -r -pe -n "CN=CertificateCommonName" -b 01/01/2000 -e 01/01/2099 –eku 1.3.6.1.5.5.7.3.3 -ss My
You should see output similar to the following:
C:\ Program Files\ Microsoft Visual Studio 8\ SDK\ v2.0\ Bin>makecert -r -pe -n "CN= Turtle Code Signing" -b 01/01/2000 -e 01/01/2099 -eku 1.3.6.1.5.5.7.3.3 -ss My Succeeded
Finally, use the following PowerShell command to verify that the certificate was installed:
PS C:\ > get-childitem cert:\ CurrentUser\ My -codesign Directory: Microsoft.PowerShell.Security\ Certificate::CurrentUser\ My Thumbprint Subject ---------- ------- 944E910757A862B53DE3113249E12BCA9C7DD0DE CN=Turtle Code Signing PS C:\ >
Method Two: CA Signed Certificate
This method is based on obtaining a code-signing certificate from a Microsoft Windows CA. These steps assume a PKI has been deployed at your organization. If not, installing Windows Certificate Services to meet your immediate need isn't recommended. Follow these steps to request a code-signing certificate:
Request that your PKI administrator create and enable a code-signing certificate template for your PowerShell scripts and configuration files.
Use Internet Explorer to access the Certificate Services Web Enrollment site at https://CAServerName/certsrv (replacing CAServerName with the name of your server).
Click the Request a Certificate link.
On the Request a Certificate page, click the Advanced certificate request link.
On the Advanced Certificate Request page, click the Create and submit a request to this CA link.
In the Certificate Template section, click to select the code-signing certificate your PKI administrator created.
Enter the rest of the identifying information and certificate request options according to your organization's certificate policy. You can use Figure 4.1 as a guideline.
Figure 4.1Example of requesting a code-signing certificate
Click the Submit button.
In the Potential Scripting Violation dialog box that opens (see Figure 4.2), click Yes to continue.
Figure 4.2Potential Scripting Violation message box
Next, if applicable, set the private key security level based on your organization's certificate policy (see Figure 4.3), and then click OK.
Figure 4.3Creating a new RSA signature key dialog box
If your organization's certificate policy requires approval from a certificate manager, then ask your certificate manager to approve the certificate request you just submitted. If approval isn't required, go to step 16.
After the certificate request has been approved, use Internet Explorer to access the Certificate Services Web Enrollment site at https://CAServerName/certsrv (replacing CAServerName with the name of your server).
Click the View the status of a pending certificate request link.
On the next page, click the appropriate certificate request link.
On the Certificate Issued page, click the Install this certificate link.
In the Potential Scripting Violation dialog box that opens (see Figure 4.4), click Yes to continue.
Figure 4.4Potential Scripting Violation message box
Finally, the Certificate Services Web Enrollment site states that the certificate was installed successfully. Use the following PowerShell command to verify the certificate installation status:
PS C:\ > get-childitem cert:\ CurrentUser\ My -codesign Directory: Microsoft.PowerShell.Security\ Certificate::CurrentUser\ My Thumbprint Subject ---------- ------- 5CBCE258711676061836BC45C1B4ACA6F6C7D09E E=Richard.Stallman@goodcode.com, C... PS C:\ >