Automation of Web Application Creation in Managed Environments (Part III: Request Certificates)

This article is based on one of my oldest scripts. It gets a certificate via the windows tool certreq.exe which is located in the system directory.

In general why would you need this script? Well you can also read each of the inputs via the command line but that will really get boring because the subject is always the same except for the hostname and all the other settings are always the same as well.

In an IT organization of a certain size you will not be the owner of the certificate authority. You might even look to use an external provider for this service. So you need to create a certificate request that somebody approves on the other end and then you will get a certificate back that you need to add to the certificate store of your server so that any communication between this server and any client can be signed with this certificate.

This is the calling script. It actually doesn’t do too much than get the input file and the actual script and will run the script with each line of the file. Don’t worry about why I did the string splitting, it is a relic from when IPs were included in the certificate as SAN (Subject Alternative Name) which is no longer something I do, because it provides machine information and thus gives and attacker information he should not have.

$path = ([string] (Split-Path -parent $MyInvocation.MyCommand.Definition))

$txtpath = ($path + "\" + "Definition.txt")
$ps1path = ($path + "\" + "Get-Certificate.ps1")

Write ("txt path: " + $txtpath)
Write ("ps1 path: " + $ps1path)

if( Test-Path($txtpath) ) {
    if( Test-Path($ps1path) ) {
        Get-Content $txtpath | Foreach-Object { 
            $splitted = $_.Split(";")
            $subdomain = $splitted[0]
            $expression = "powershell.exe $ps1path $subdomain"
            invoke-expression $expression;
    } else {
        Write "Error finding resource file:"
        Write ("ps1 file (" + $ps1path + ") should be in the same directory as this script")
} else {
    Write "Error finding resource files:"
    Write "txt and ps1 files with name of server should be in the same directory as this script"

The more interesting of the two scripts is actually the core or callee script, which brings everything together. It takes the input parameter and meshes that with all the static information to create an input file that will in turn be passed to certreq.exe that will then create a certificate request. So you might say it is a certificate request request. 😉

The interesting part of the script is actually the naming of the certificate file. It gets the server name via the DNS Class and adds the fqdn to it. The certificate will have .cer as an extension. The input file has .txt as an extension and the request has .req as an extension. Any files that are no longer needed are cleaned up during the process and before a new certificate is created the script deletes any old certificates. You can also see that the key length is 2048. So that’s hopefully pretty secure. The input file has a specific format, so that’s the reason why I write each line separately. You can see that at one point I missed to add the hyphens to the subject before adding it to the file. That was basically not such a good idea. It created certificates, but they did not work as expected.

$path = ([string] (Split-Path -parent $MyInvocation.MyCommand.Definition))

if ($args -eq $null -or $args.Length -lt 1) {
    Write "Usage: "
    Write "------ "
    Write "Param 1 - fqdn"
} else {
    Write ("argument 1: " + $args[0])
    $server = [System.Net.Dns]::GetHostName()
    $FQDN = $args[0].ToUpper()
    $name = ($server + "_" + $FQDN);
    $subfolder = (Get-Date).ToString("yyyy-MM-dd");
    $outpath = ($path + "\" + $subfolder + "\");
    if(-not (test-path($outpath))) {
        $f = new-item -Path $outpath -ItemType "Directory";

    $txtFile = ($outPath + $name + ".req.txt")
    $outFile = ($outPath + $name + ".req")
    $subject = ("CN=" + "$FQDN,,OU=Global IT,O=meiringer AG,L=Wiesbaden,S=Hesse,C=DE")
    $san = "dns=$FQDN"
    Write ("name: " + $name)
    Write ("outPath: " + $outPath);
    Write ("outFile: " + $outFile);
    Write ("txtFile: " + $txtFile);

        Remove-Item $txtFile -confirm:$false
        Remove-Item $outFile -confirm:$false
    Write ("subject: " + $subject)
    Write ("san: " + $san)
    Write "[Version]" > $txtFile
    Write ("txtFile = `"`$Windows NT`$`"") >> $txtFile
    Write "" >> $txtFile
    Write "[NewRequest]" >> $txtFile
    Write ("Subject = `"" + $subject + "`"")  >> $txtFile
#    Write ("Subject = " + $subject)  >> $filePath
    Write "KeySpec = 1" >> $txtFile
    Write "KeyLength = 2048" >> $txtFile	  	
    Write "KeyUsage = 0x30" >> $txtFile 	  	
    Write "RequestType = CMC" >> $txtFile
    Write "ProviderName = `"Microsoft RSA SChannel Cryptographic Provider`"" >> $txtFile
    Write "Providertype = 12" >> $txtFile
    Write "SMIME = FALSE" >> $txtFile
    Write "SILENT = TRUE" >> $txtFile
    Write "MACHINEKEYSET = TRUE" >> $txtFile
    Write "" >> $txtFile
    Write "[RequestAttributes]" >> $txtFile
#    Write ("SAN = `"" + $san + "`"") >> $filePath
    Write ("SAN = " + $san) >> $txtFile
    $execPath = "C:\Windows\System32\certreq.exe"
    Invoke-Expression -command "$execPath -New -machine $txtFile $outFile"
        Remove-Item $txtFile -confirm:$false

The last part is basically invoking the certifcate request tool with the textfile and outfile as parameters. The script will basically open a few windows while it runs, but it is quite quick so that’s not going to be too irritating. I should also mention that you can add multiple Subject Alternative Names, if you like. All you need to do is separate them by commas and you are good to go. If you want to do that, piece them together explicitly to keep a single identifier available or add another parameter for the name. The subject is basically only necessary for identification, then SAN part is what will later be used for the web sites and need to fit to the host names.

For completion sake this is what the input file “definitions.txt” looks like. Each line represents a hostname and thus will result in a certificate.


Continue Reading…Part IV

Back To Part II
Back To Overview



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: