A Little Dusty   1 comment

I need to blow the dust off this sight.

About 2 months ago I rejoined the PowerShell team after a 7 year hiatus. I’ve continued to use PowerShell everyday, and I’m excited to be part of the team again. I had been in the Office org working on Office online services and most of the PowerShell work I did was pretty specific to that, so I didn’t really have much to share. That condition has changed, so I expect I’ll have more to share.

One of the issues that we had when working with online services was certificate replacement. From a security perspective, you want to be able to replace certificates on a fairly regular basis; however, it’s sometimes hard to be sure that you’re not changing more than you should when you get a new cert (we had that problem quite a bit). To that end, I created a certificate comparison script which helped make sure that the new cert would not have the wrong changes. It allows you to compare arbitrary properties or extensions of two certificates (public (cer) or private (pfx)) so you could easily see if the new certificate was consistent with the prior cert in the places it should, and have only the changes (usually NotBefore and NotAfter).

Here’s the script:

[CmdletBinding()]
param (
    [Parameter(Position=0,Mandatory=$true,ParameterSetName="pfx")]$pfx1,
    [Parameter(Position=1,Mandatory=$true,ParameterSetName="pfx")]$pass1,
    [Parameter(Position=2,Mandatory=$true,ParameterSetName="pfx")]$pfx2,
    [Parameter(Position=3,Mandatory=$true,ParameterSetName="pfx")]$pass2,
    [Parameter(Position=0,Mandatory=$true,ParameterSetName="cer")]$cer1,
    [Parameter(Position=1,Mandatory=$true,ParameterSetName="cer")]$cer2,
    [Parameter()]$properties = @("NotBefore","NotAfter","Subject","Issuer"),
    [Parameter()]$extensions = "Key Usage",
    [Parameter()][switch]$raw
    )

BEGIN
{
    $X509T = "System.Security.Cryptography.X509Certificates.X509Certificate2"
}
END

{
    if ( $PSCmdlet.ParameterSetName -eq "pfx")
    {
        $fullname = (get-item $pfx1).fullname
        $cert1 = new-object $X509T ([io.file]::ReadAllBytes($fullname)),$pass1
        $fullname = (get-item $pfx2).fullname
        $cert2 = new-object $X509T ([io.file]::ReadAllBytes($fullname)),$pass2
        $file1 = $pfx1
        $file2 = $pfx2
        if ( $file1 -eq $file2 ) { $file2 = "${file2} (2)" }
    }
    else
    {
        $fullname = (get-item $cer1).fullname
        $cert1 = new-object $X509T $fullname
        $fullname = (get-item $cer2).fullname
        $cert2 = new-object $X509T $fullname
        $file1 = $cer1
        $file2 = $cer2
        if ( $file1 -eq $file2 ) { $file2 = "${file2} (2)" }
    }
   
    $collection = @()
    foreach($property in $properties)
    {
        $collection += new-object psobject -prop @{
            Property = $property
            $file1 = $cert1.$property
            $File2 = $cert2.$property
            Different = $cert1.$property -ne $cert2.$property
            }
    }
    foreach ( $extension in $extensions)
    {
        $v1 = $cert1.Extensions|%{$_.oid}|?{$_.friendlyname -eq "$extension"}|%{$_.value}
        $v2 = $cert2.Extensions|%{$_.oid}|?{$_.friendlyname -eq "$extension"}|%{$_.value}
        $k = $Extension -replace " "
        $collection += new-object psobject -prop @{
            Property = $k
            $File1 = $v1
            $File2 = $v2
            Different = $v1 -ne $v2
            }
    }
    if ( $raw )
    {
        $cert1
        $cert2
        ,$collection
    }
    else
    {
        $collection|ft @{ L="Property";W = 14; E={$_.property}},@{L="Different";W=10;E={$_.different}},$file1,$file2
    }
}

Because this was a tool for our service engineers to use, I provide formatted data, rather than raw objects. However, if you use the –Raw switch, you’ll get the certs that you’re comparing as well as the collection of differences. Here’s an example of output (using a cert provided by the network tool ‘fiddler2’)

 

PS# .\Compare-Certificate.ps1 -pfx1 C:\temp\fiddlerCert.pfx -pfx2 C:\temp\fiddlerCert.pfx

cmdlet Compare-Certificate.ps1 at command pipeline position 1
Supply values for the following parameters:
pass1:
pass2:

Property        Different C:\temp\fiddlerCert.pfx                                  C:\temp\fiddlerCert.pfx (2)
——–        ——— ———————–                                  —————————
NotBefore           False 8/2/2013 12:00:00 AM                                     8/2/2013 12:00:00 AM
NotAfter            False 8/1/2024 11:59:59 PM                                     8/1/2024 11:59:59 PM
Subject             False CN=clients1.google.com, O=DO_NOT_TRUST, OU=Created by… CN=clients1.google.com, O=DO_NOT_TRUST, OU=Created by…
Issuer              False CN=DO_NOT_TRUST_FiddlerRoot, O=DO_NOT_TRUST, OU=Creat… CN=DO_NOT_TRUST_FiddlerRoot, O=DO_NOT_TRUST, OU=Creat…
KeyUsage            False

Since it’s the same cert in this case, there’s no differences. That in itself would be pretty handy if you gotten a new cert and it was identical to the old cert.

Advertisements

Posted September 24, 2014 by jtruher3 in PowerShell

One response to “A Little Dusty

Subscribe to comments with RSS.

  1. Welcome back Jim! Looking forward to seeing your session next week in Amsterdam 🙂

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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: