| # http://www.bouncycastle.org/csharp/ | |
| $BouncyCastlePath = 'Path\To\BouncyCastle.Crypto.dll' | |
| $BouncyCastle = Add-Type -Path $BouncyCastlePath -PassThru | |
| function Get-TrustedRootCertificateHash { | |
| [OutputType([String])] | |
| [CmdletBinding()] | |
| param ( | |
| [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] | |
| [Alias('FullName')] | |
| [ValidateNotNullOrEmpty()] | |
| [String] | |
| $Path | |
| ) | |
| # Note: you should always be able to download the latest authroot.stl from: | |
| # http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootstl.cab | |
| # You could then download each certificate directly from Microsoft for comparison: e.g. | |
| # http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/CDD4EEAE6000AC7F40C3802C171E30148030C072.crt | |
| # Where CDD4EEAE6000AC7F40C3802C171E30148030C072 is one of the present certificate hash values | |
| # Thanks to http://unmitigatedrisk.com/?p=259 for this information. | |
| $FullPath = Resolve-Path -Path $Path | |
| $FileInfo = Get-Item -Path $FullPath | |
| if ($FileInfo.Name -ne 'authroot.stl') { | |
| Write-Error "You must specify the following filename: authroot.stl." | |
| return | |
| } | |
| $FileStream = [IO.File]::OpenRead($FullPath) | |
| if (-not $FileStream) { continue } | |
| $ASN1InputStream = New-Object -TypeName Org.BouncyCastle.Asn1.Asn1InputStream -ArgumentList $FileStream | |
| $ASN1Object = $ASN1InputStream.ReadObject() | |
| if (-not $ASN1Object) { | |
| Write-Error "$FullPath is not ASN.1 encoded data." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if (($ASN1Object.Count -lt 2)) { | |
| Write-Error "$($FullPath): ASN.1 encoded data does not hold enough information to hold PKCS#7 ASN.1 SignedData (1.2.840.113549.1.7.2)." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if (-not ($ASN1Object[0] -is [Org.BouncyCastle.Asn1.DerObjectIdentifier])) { | |
| Write-Error "$($FullPath): ASN.1 encoded data is not PKCS#7 ASN.1 SignedData (1.2.840.113549.1.7.2). It must contain an OID datatype." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if ($ASN1Object[0].Id -ne '1.2.840.113549.1.7.2') { | |
| Write-Error "$($FullPath): ASN.1 encoded data is not PKCS#7 ASN.1 SignedData. Its OID must be 1.2.840.113549.1.7.2." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if (-not ($ASN1Object[1] -is [Org.BouncyCastle.Asn1.DerTaggedObject])) { | |
| Write-Error "$($FullPath): ASN.1 encoded data is not PKCS#7 ASN.1 SignedData (1.2.840.113549.1.7.2). It must contain a context-specific tag." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if (($ASN1Object[1].TagNo -ne 0) -or ($ASN1Object[1].IsEmpty())) { | |
| Write-Error "$($FullPath): ASN.1 encoded data is not PKCS#7 ASN.1 SignedData (1.2.840.113549.1.7.2). It must contain a non-empty context-specific tag ([0])." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| $SignedDataObject = $ASN1Object[1].GetObject() | |
| # Check that the sequence count is at least 3: version, hash algorithm, and CTL entry list | |
| if ($SignedDataObject.Count -lt 3) { | |
| Write-Error "$($FullPath): Certificate trust list data must have at least three sections representing the version, hash algorithm, and CTL entries." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if ((-not ($SignedDataObject[0] -is [Org.BouncyCastle.Asn1.DerInteger])) -or ($SignedDataObject[0].Value.IntValue -ne 1)) { | |
| Write-Error "$($FullPath): Inproper version field. The version field must be set to 1." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| $SHA1Algorithm = '1.3.14.3.2.26' | |
| if ($SignedDataObject[1].GetObjectAt(0)[0].Id -ne $SHA1Algorithm) { | |
| Write-Error "$($FullPath): Hashing algorithm is not set to SHA1 ($SHA1Algorithm)." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if ($SignedDataObject[2][0].Id -ne '1.3.6.1.4.1.311.10.1') { | |
| Write-Error "$($FullPath): A valid certificate trust list (1.3.6.1.4.1.311.10.1) is not present." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| $CTLSequence = $SignedDataObject[2][1].GetObject() | |
| if ($CTLSequence[0].Id -ne '1.3.6.1.4.1.311.10.3.9') { | |
| Write-Error "$($FullPath): CTL does not have a Root List Signer tag (1.3.6.1.4.1.311.10.3.9)." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| # Skip over the sequence number and update times | |
| # The SHA1 algorithm identifier should repeat here. | |
| if ($CTLSequence[3][0].Id -ne $SHA1Algorithm) { | |
| Write-Error "$($FullPath): Hashing algorithm is not set to SHA1 ($SHA1Algorithm)." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| if ((-not ($CTLSequence[4] -is [Org.BouncyCastle.Asn1.DerSequence])) -or ($CTLSequence.Count -lt 1)) { | |
| Write-Error "$($FullPath): No CTL entries are present." | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| return | |
| } | |
| $CTLSequence[4] | ForEach-Object { | |
| $_[0][0].ToString().TrimStart('#').ToUpper() | |
| } | |
| $ASN1InputStream.Close() | |
| $FileStream.Close() | |
| } | |
| Get-TrustedRootCertificateHash -Path authroot.stl |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment