3

I am using signtool to sign my msi and setup.exe files.

Timestamping failed for most of the msi, Now i would like to timestamp them separately.

How to find whether timestamp is missing or not?

Following cmdlet helps me to find whether it is signed or not

$AuthStatus= (Get-AuthenticodeSignature $FILENAME)

    If ($AuthStatus.status -ne "Valid") {

               $SIGNTOOL sign /v /f $CERPFX /t $TimestampSRVR /p $PWD $FILENAME
        }

Now i need to check whether the msi timestamp is missing or not, How to do it?

Samselvaprabu
  • 16,830
  • 32
  • 144
  • 230
  • 1
    What do you mean by 'Timestamping'? Which property of Get-AuthenticodeSignature it is mapped to? – Shay Levy Jan 31 '12 at 14:29
  • @Shay Levy: In Signtool.exe , we will sign and timestamp. [If the msi is signed]If we right click on the msi and see properties ,it will have tab called 'Digital signature'. If you click on Digital signature tab, it will have timestamp column. Now it is empty for me. I don't the exact property which match this. – Samselvaprabu Jan 31 '12 at 14:33
  • See this [SO post](http://stackoverflow.com/questions/3281057/get-timestamp-from-authenticode-signed-files-in-net) for one possible approach to determining if there is a timestamp. – Keith Hill Jan 31 '12 at 21:11

2 Answers2

2

Finally i found answer by myself. There is a property named "TimeStamperCertificate " is there it seems. Following is the code snippet.

If the msi is not signed or timestamped , It will sign and timestamp again.

$MsiAuthInfo= (Get-AuthenticodeSignature $FILENAME)

    If ($MsiAuthInfo.status -ne "Valid" -or $MsiAuthInfo.TimeStamperCertificate -eq $Null) {

               $SIGNTOOL sign /v /f $CERPFX /t $TimestampSRVR /p $PWD $FILENAME
        }
Samselvaprabu
  • 16,830
  • 32
  • 144
  • 230
1

Here's a PowerShell solution courtesy of PowerShell MVP Vadims Podans. Get-AuthenticodeSignatureEx adds a SigningTime property to the result, the value is a datetime as generalized time (not local time), you can always call the ToLocalTime() on the datetime object to get the result in your time zone. You can use the following command to quickly test it:

dir $pshome\*.ps1xml | Get-AuthenticodeSignatureEx | ft SignerCertificate,Status,SigningTime,Path


function Get-AuthenticodeSignatureEx
{
    [CmdletBinding()]

    param(
        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
        [String[]]$FilePath
    )

    begin
    {
        $signature = @"
        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CryptQueryObject(
            int dwObjectType,
            [MarshalAs(UnmanagedType.LPWStr)]string pvObject,
            int dwExpectedContentTypeFlags,
            int dwExpectedFormatTypeFlags,
            int dwFlags,
            ref int pdwMsgAndCertEncodingType,
            ref int pdwContentType,
            ref int pdwFormatType,
            ref IntPtr phCertStore,
            ref IntPtr phMsg,
            ref IntPtr ppvContext
        );
        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CryptMsgGetParam(
            IntPtr hCryptMsg,
            int dwParamType,
            int dwIndex,
            byte[] pvData,
            ref int pcbData
        );
        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CryptMsgClose(
            IntPtr hCryptMsg
        );
        [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CertCloseStore(
            IntPtr hCertStore,
            int dwFlags
        );
"@
        Add-Type -AssemblyName System.Security
        Add-Type -MemberDefinition $signature -Namespace PKI -Name Crypt32
    }

    process
    {
        Get-AuthenticodeSignature @PSBoundParameters | ForEach-Object {
            $Output = $_
            if ($Output.SignerCertificate -ne $null) {
                $pdwMsgAndCertEncodingType =  0
                $pdwContentType =  0
                $pdwFormatType =  0
                [IntPtr]$phCertStore = [IntPtr]::Zero
                [IntPtr]$phMsg = [IntPtr]::Zero
                [IntPtr]$ppvContext = [IntPtr]::Zero
                $return = [PKI.Crypt32]::CryptQueryObject(
                    1,
                    $_.Path,
                    16382,
                    14,
                    $null,
                    [ref]$pdwMsgAndCertEncodingType,
                    [ref]$pdwContentType,
                    [ref]$pdwFormatType,
                    [ref]$phCertStore,
                    [ref]$phMsg,
                    [ref]$ppvContext
                )

                $pcbData = 0
                $return = [PKI.Crypt32]::CryptMsgGetParam($phMsg,29,0,$null,[ref]$pcbData)
                $pvData = New-Object byte[] -ArgumentList $pcbData
                $return = [PKI.Crypt32]::CryptMsgGetParam($phMsg,29,0,$pvData,[ref]$pcbData)
                $SignedCms = New-Object Security.Cryptography.Pkcs.SignedCms
                $SignedCms.Decode($pvData)
                foreach ($Infos in $SignedCms.SignerInfos) {
                    foreach ($CounterSignerInfos in $Infos.CounterSignerInfos) {
                        $sTime = ($CounterSignerInfos.SignedAttributes | Where-Object {$_.Oid.Value -eq "1.2.840.113549.1.9.5"}).Values | Where-Object {$_.SigningTime -ne $null}
                    }
                }
                $Output | Add-Member -MemberType NoteProperty -Name SigningTime -Value $sTime.SigningTime -PassThru -Force
                [void][PKI.Crypt32]::CryptMsgClose($phMsg)
                [void][PKI.Crypt32]::CertCloseStore($phCertStore,0)
            } else {
                $Output
            }
        }    
    }
}
Shay Levy
  • 121,444
  • 32
  • 184
  • 206