Streamlining the non-store code signing process

At Poll Everywhere, we have a PowerPoint plugin that is released independently of any app store. Last year, we completed our SOC II certification, which requires an annual certificate and key rotation. Because of this, I went through the process of rotating our signing certificate and keys on the Windows platform.

After a lengthy manual process using the Microsoft Management Console (MMC) it was easy to see how many articles rely on it. It is a nice tool for manually generating signing components. But, if you want to streamline your process you’ll need to be familiar with a few more concepts and tools.

Great tools for automation already exist for apps that live in an app store. Using MMC to generate certificates, you will find scattered resources and lengthy technical documentation on tools you only need to use small parts of. Understanding the fundamentals will give you a better understanding of what’s happening.

In this article series, you will discover the components of a Certificate Signing Request (CSR), tools you can use to automate generation of a CSR, install signing certificates, and export them for backup. This process requires understanding the following:

  • Encryption basics
    • What are keys?
    • Private and public
  • Certificates
    • What are Secure Sockets Layer (SSL) Certificates?
    • What is a Certificate Authority (CA)?
    • What is a Certificate Chain?
    • What does Code Signing do?
  • Certificate Signing Requests
    • What is a Certificate Signing Request?
    • How to generate a CSR
    • Handling the CSR response

Encryption basics

Encryption comes in many forms, but as far as code signing is concerned, two keys are involved. A public and a private key. We sign a binary with the private key, and attach the public key with a certificate to guarantee authenticity, and we can securely sign and verify code.

What are keys?

Keys are used to encrypt and decrypt data. Keys break down into two major categories: symmetric and asymmetric.

Symmetric

Symmetric encryption involves only one key. The same key is used to both encrypt and decrypt data. A simple example of this is a caesar cipher. This cipher replaces one letter with another for each letter in an alphabet. The key defines how letters are replaced. For example, a key that rotates the alphabet by one letter would look like this:

  a -> b
  b -> c
  c -> d
  …
  z -> a

“The quick brown fox” encrypts to:
“uif rvjdl cspxo gpy”, which decrypts to the original message using the inverse key:

  b -> a
  c -> b
  d -> b
  …
  a -> z

Modern encryption generates these keys algorithmically.

Asymmetric

Asymmetric encryption, otherwise known as public key encryption, involves two keys: one public and one private. The public key is safe for anyone to see, while the private key must stay hidden.

Keys are a sequence of binary data of a specified length. Typically this data is encoded before storing in a file or transmitting to remote systems.

Certificates are signed with asymmetric encryption. The private key is used in the signature and the public key is attached. The public key is then used to verify the signature of the data.

Private and Public

From an unencrypted private key you can generate a public key. If your private key is encrypted to begin with, you need the passcode to decrypt and then use. Once decrypted, it can be used to generate the public key. It is generally a bad Idea to store the private key unencrypted. If someone gets a hold of your signing certificate with a copy of your unencrypted private key, they can impersonate you, as long as they have your certificate.

The two main standards for key pairs are RSA and ECDSA. Both are considered secure if you meet the minimum key length requirements. RSA is an older standard used across many systems. It is still around for backwards compatibility but still considered effective when using long keys. ECDSA is a newer standard, better for mobile devices, as the key length is shorter and requires less data to transfer. For code signing, either works.

Key length for ECDSA only requires 112-bits to match the same level of security for a RSA 2048-bit key. The EC in ECDSA stands for Elliptical Curve, and as such, ECDSA key generation requires a curve parameter. The curve parameter defines the elliptical curve that is used in calculating values for encryption as well as the maximum bit length for private keys. Here is a great video explaining the basics of ECDSA encryption if you want to learn more.

Typically the tools used to generate these keys will either be able to list the options, or have the options documented. To see openssl’s curve list, run:

  
    openssl ecparam -list_curves 
  

RSA key generation can be of many lengths, but for code signing a 2048-bit minimum should be used. To generate an RSA key, you only need to specify bit-length. When generating a key, you have the option to specify a password to encrypt it. Here are some interesting details about RSA and ECDSA:

  • Many encryption systems rely on RSA because ECDSA is a slightly newer standard. RSA is significantly faster than ECDSA in verifying signatures, though it is slower while signing.
  • Encrypting and decrypting using asymmetric keys is on the order of 1,000x slower than symmetric keys. Many SSL connections use asymmetric encryption to establish a connection. Then, after the connection is established, they send an encrypted symmetric key that both parties use for the sake of performance.
  • Keys are composed of bits. The encryption standard for security level is also measured in bits. They don’t mean the same thing. Key length bits are the number of 1s and 0s that go into a key. The security level relates to the number of operations an attacker needs to perform to compromise a key’s security.
  • ECDSA requires much smaller public keys. A 112-bit security level RSA public key requires a length of 2048-bits. ECDSA keys for the same security level only require 224-bits. This fact makes EDCSA better for mobile connections.
  • ECDSA is the default when generating a CSR using the Microsoft tool chain.

Any RSA examples used below are referring to RSA 2048-bit length keys.

Certificates

Let us break down certificates.

What are SSL Certificates?

Certificates establish a chain of trust. They prevent malicious actors from impersonating someone during a connection, or after signing a binary with a private certificate. Certificates typically contain information about whoever signed it along with the entity’s public key. Your cert represents you.

What is a Certificate Authority?

A Certificate Authority (CA) typically represents a gold standard as a source of trust. Many times browsers are considered trusted entities.

A CA is accepted by whomever would have to verify a signature. Microsoft trusts their own set of CAs. Google has a list for Android. Any operating system vendor will have their own list. Browsers can manage their own lists as well.

Certificate Authorities sign certificates. Often they are quite expensive. Let’s Encrypt offers free signatures. I used them to learn more about this process.

What is a Certificate Chain?

A Certificate Chain is composed of SSL Certificates that are signed by a Certificate Authority. It typically contains a Root Certificate (CA Cert) followed by a second CA certificate. Any chain that follows the root certificate is known as an intermediary certificate. Then, usually the certificate that you would request at the end of the chain. A certificate chain doesn’t have to follow this pattern, a chain can have any number of intermediary certs. This chain ensures that your certificate has not been tampered with.

What does code signing do?

How does this certificate chain ensure that a binary hasn’t been tampered with? Great question. When signing a binary, a cryptographic hash is generated from the binary itself.

That cryptographic hash then has an operation performed on it using the private key. The combination of these things is the signature. Set it aside for use in a moment.

A fingerprint (or “thumbprint” in Internet Explorer terms) is a cryptographic hash digest, usually used to identify a public key. The literal definition of a fingerprint is “the MD5 digest of the der-encoded certificate info”. The fingerprint is also calculated from the binary, but used to reference the public key. Since the key or certificate’s fingerprint is unique, it is used as a reference to save time as opposed to going through all of your certificates and public keys, and generating hashes of everything.

The fingerprint, along with the signature, as well as the certificate chain are then attached to the end of the binary in a special region.

If any bits of the binary have changed since the binary was signed, the hash produced will be different. This is how signed code guarantees that it has not been tampered with.

What is a Certificate Signing Request?

A Certificate Signing Request (CSR) is a request you send to a CA containing information that identifies yourself. The CA validates the request, attaches the certificate containing your public key to the end of the certificate chain, and responds with the result.

Note: if you generate a CSR with MMC, stick with the Microsoft toolchain (certreq, certutil) through the end to minimize problems. Avoid mixing openssl with certreq and certutil. The output can differ slightly producing incompatible results.

How to generate a CSR


With openssl:

Use this command line to generate a new private key along with the certificate request in one step. The private key in this case is not protected. Take a look at the -passout argument to password protect the private key (suggested).

The following line will generate an unencrypted private key to go along with the public key specified in the CSR. This private key is important, keep it secure. You will need it when you receive the signed certificate from your CA.

  
    openssl req -new -newkey rsa:2048 -keyout . -out  -subj "/C=/ST=/L=/O=/CN="
  


With certreq:

The Windows toolchain (certreq) manages the private key for you. You can extract the private key prior to generating a CSR, but that is not covered here. This next snippet is a powershell script that creates a .inf file and generates the CSR for you. The information stored in the .inf file is used by certreq to generate the CA.

  
    Invoke-Command -ScriptBlock {
    $CertName = ""
    $CSRPath = "$($CertName).csr"
    $INFPath = "$($CertName).inf"
    Write-Host "  Creating CertificateRequest(CSR) for $CertName `r "
    $INF =
    @"
    [Version]
    Signature= "$Windows NT$"
    [NewRequest]
    Subject = "CN=, OU=, L=, ST=, C="
    KeySpec = 1
    KeyLength = 2048
    Exportable = TRUE
    MachineKeySet = TRUE
    SMIME = False
    PrivateKeyArchive = FALSE
    UserProtected = FALSE
    UseExistingKeySet = FALSE
    ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
    ProviderType = 12
    RequestType = PKCS10
    KeyUsage = 0xa0
    [EnhancedKeyUsageExtension]
    OID=1.3.6.1.5.5.7.3.3
    "@
    write-Host "  Certificate Request ($CSRPath) is being generated `r "
    $INF | out-file -filepath $INFPath -force
    certreq -new $INFPath $CSRPath
    }
    write-output "If no errors occurred, Certificate Request was generated here"
  

If you want to learn more about the usage fields, look them up in certreq’s documentation. Know that 0xa0 and the OID fields are set above to allow code signing as well as data transmission encryption.

To verify the information contained in the above CSR:

  
    openssl req -in .csr -noout -text
  

Send the .csr off to your CA.

Handling the CSRs response.

When the CA responds, assuming there is nothing to correct in the request, they will give you the signed cert chain back. The file types vary, but SPC or .CER files are common. Replace cer with spc in the next example if you receive an spc in response.

Use certutil to import it.

  
    certutil -addstore -f MY .cer
  

When you import the certificate, windows will associate the private key with the cert. Back up the certificate by exporting it. You need to export it with the PKCS12 format. This format includes both the certificate chain as well as the private key. It is a good idea to export the private key with a password. If you don’t and it is leaked, you’ll have to go through the whole process again and redact the key through your CA! The key revocation process is archaic and relies on the OS vendor to accept a Certificate Revocation List from the Certificate Authority. It’s a hassle, just use a password to encrypt your private keys.

Here’s a quick and dirty script to help out finding and exporting your PKCS12 PFX file. If you don’t want to use a potentially insecure environment variable, modify it to fit your needs.

The important line is at the end, read:certutil. The rest is there to help find the cert automatically.

  
    $found_certs = (Get-ChildItem -path Cert:\LocalMachine\My | where {$_.Subject -like '**'})
    if($Env:PFXPASS -eq $null)
    {
      Write-Host "Please set PFXPASS before exporting"
      exit
    }
    if($test.Count -eq 0)
    {
      Write-Host $"no matches to  found in the Cert:\LocalMachine\My store"
      Write-Host $"Try this in powershell:"
      Write-Host $"Get-ChildItem -path Cert:\LocalMachine\My | where {$_.Subject -like '**'}"
      exit
    }
    Write-Host $found_certs[0].Thumbprint
    $pfxFile = ""
    Write-Host "outputting to " $pfxFile
    certutil -exportPFX -p $Env:PFXPASS My $found_certs[0].Thumbprint $pfxFile
  

Back up that .pfx file somewhere safe and you’re done.
Congratulations! You now have a grasp on encryption keys, certificates, certificate authorities, and certificate signing requests! If you followed the steps above you can now sign certificates on windows.

Hungry for more? If you have an hour to spare and want another great explanation of the components discussed above and more I suggest watching Demystifying SSL, by Mislav Kos. I learned quite a bit from it.

If you want a Windows reference, I suggest Digital Privacy and Security Using Windows: A Practical Guide