diagnosticsModule/Private/CertificateChecks.ps1

Function Test-CertificateAvailable
{
    param(
        [Parameter(HelpMessage="Single element of list Generated by Get-AdfsCertificatesToTest")]
        $certificateAvailable,  
        [string]
        $certificateType,
        [bool]
        $isPrimary = $true,
        [string]
        $notRunReason
    )
    
    $testName = Create-CertCheckName -certType $certificateType -checkName "NotFoundInStore" -isPrimary $isPrimary

    if (-not $certificateAvailable -and [String]::IsNullOrEmpty($notRunReason))
    {
        $notRunReason = "Certificate object is null."
    }
    
    if (-not [String]::IsNullOrEmpty($notRunReason))
    {
        return Create-CertificateCheckResult -certCheckResult $null -testName $testName -result NotRun -detail $notRunReason
    }

    
    try
    {
        $thumbprint = $certificateAvailable.Thumbprint
        $testResult = New-Object TestResult -ArgumentList($testName)
        $testResult.Result = [ResultType]::NotRun;
        $testResult.Output = @{$tpKey = $thumbprint}
        
        if ($certificateAvailable.StoreLocation -eq "LocalMachine")
        {
            $certStore = New-Object System.Security.Cryptography.X509Certificates.X509Store($certificateAvailable.StoreName,`
                [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine)
            try
            {
                $certStore.Open("IncludeArchived")
                
                $certSearchResult = $certStore.Certificates | where {$_.Thumbprint -eq $thumbprint}
                if (($certSearchResult | measure).Count -eq 0)
                {
                    $testResult.Detail = "$certificateType certificate with thumbprint $thumbprint not found in LocalMachine\{0} store.`n" -f $certificateAvailable.StoreName
                    $testResult.Result = [ResultType]::Fail
                }
                else
                {
                    $testResult.Result = [ResultType]::Pass
                }
            }
            catch
            {
                $testResult.Result = [ResultType]:: NotRun;
                $testResult.Detail = "$certificateType certificate with thumbprint $thumbprint encountered exception with message`n" + $_.Exception.Message
            }
            finally
            {
                $certStore.Close()
            }
        }
        else
        {
            $testResult.Result = [ResultType]:: NotRun;
            $testResult.Detail = "$certificateType certificate with thumbprint $thumbprint not checked for availability because it is in store: " + $certificateAvailable.StoreLocation
        }
        
        return $testResult
    }
    catch [Exception]
    {
        return Create-NotRunExceptionTestResult $testName $_.Exception.Message
    }
}

function Test-CertificateExpired
{
    param (
        [System.Security.Cryptography.X509Certificates.X509Certificate2] 
        $certExpired,
        [string]
        $certificateType,
        [bool]
        $isPrimary = $true,
        [string]
        $notRunReason
    )
    
    $checkName = "Expired"
    
    $testName = Create-CertCheckName -certType $certificateType -checkName $checkName -isPrimary $isPrimary
    
    if (-not $certExpired -and [String]::IsNullOrEmpty($notRunReason))
    {
        $notRunReason = "Certificate object is null."
    }
    if (-not [String]::IsNullOrEmpty($notRunReason))
    {
        return Create-CertificateCheckResult -certCheckResult $null -testName $testName -result NotRun -detail $notRunReason
    }
    
    try
    {
        if (Verify-IsCertExpired -isCertExpired $certExpired)
        {
            $tp = $certExpired.Thumbprint

            $certificateExpiredTestDetail = "$certificateType certificate with thumbprint $tp has expired.`n";
            $certificateExpiredTestDetail += "Valid From: " + $certExpired.NotBefore.ToString() + "`nValid To: " + $certExpired.NotAfter.ToString();
            $certificateExpiredTestDetail += "`nAutoCertificateRollover Enabled: " + (Retrieve-AdfsProperties).AutoCertificateRollover + "`n";
            return Create-CertificateCheckResult -certCheckResult $certExpired -testName $testName -result Fail -detail $certificateExpiredTestDetail 
        }
        else
        {    
            return Create-CertificateCheckResult -certCheckResult $certExpired -testName $testName -result Pass
        }
    }
    catch [Exception]
    {
        return Create-NotRunExceptionTestResult $testName $_.Exception.Message
    }
}

function Test-CertificateAboutToExpire
{

    param (
        [System.Security.Cryptography.X509Certificates.X509Certificate2] 
        $certAboutToExpire,
        [string]
        $certificateType,
        [bool]
        $isPrimary = $true,
        [string]
        $notRunReason
    )
    $checkName = "AboutToExpire"
    
    $testName = Create-CertCheckName -certType $certificateType -checkName $checkName -isPrimary $isPrimary
    
    $expiryLimitInDays = 90;

    
    if (-not $certAboutToExpire -and [String]::IsNullOrEmpty($notRunReason))
    {
        $notRunReason = "Certificate object is null."
    }
    if (-not [String]::IsNullOrEmpty($notRunReason))
    {
        return Create-CertificateCheckResult -certCheckResult $null -testName $testName -result NotRun -detail $notRunReason
    }
    
    try
    {
        $properties = Retrieve-AdfsProperties
        if ($properties.AutoCertificateRollover -and ($certificateType -eq "Token-Decrypting" -or $certificateType -eq "Token-Signing"))
        {
            return Create-CertificateCheckResult -certCheckResult $certAboutToExpire -testName $testName -result NotRun -detail "Check Skipped when AutoCertificateRollover is enabled"
        }

        $expirtyMinusToday = [System.Convert]::ToInt32(($certAboutToExpire.NotAfter - (Get-Date)).TotalDays);
        if ($expirtyMinusToday -le $expiryLimitInDays)
        {
            $tp = $certAboutToExpire.Thumbprint

            $certificateAboutToExpireTestDetail = "$certificateType certificate with thumbprint $tp is about to expire in $expirtyMinusToday days.`n"
            $certificateAboutToExpireTestDetail += "Valid From: " + $certAboutToExpire.NotBefore.ToString() + "`nValid To: " + $certAboutToExpire.NotAfter.ToString();
            $certificateAboutToExpireTestDetail += "`nAutoCertificateRollover Enabled: " + (Retrieve-AdfsProperties).AutoCertificateRollover + "`n";
            return Create-CertificateCheckResult -certCheckResult $certAboutToExpire -testName $testName -result Fail -detail $certificateAboutToExpireTestDetail 
        }
        else
        {    
            return Create-CertificateCheckResult -certCheckResult $certAboutToExpire -testName $testName -result Pass
        }
    }
    catch [Exception]
    {
        return Create-NotRunExceptionTestResult $testName $_.Exception.Message
    }
}

function Test-CertificateHasPrivateKey
{
    param (
        [System.Security.Cryptography.X509Certificates.X509Certificate2] 
        $certHasPrivateKey,
        [string]
        $certificateType,
        [bool]
        $isPrimary = $true,
        [string]
        $storeName,
        [string]
        $storeLocation,
        [string]
        $notRunReason
    )
    
    $checkName = "PrivateKeyAbsent"
    
    $testName = Create-CertCheckName -certType $certificateType -checkName $checkName -isPrimary $isPrimary

    if (-not $certHasPrivateKey -and [String]::IsNullOrEmpty($notRunReason))
    {
        $notRunReason = "Certificate object is null."
    }
    
    if (-not [String]::IsNullOrEmpty($notRunReason))
    {
        return Create-CertificateCheckResult -certCheckResult $null -testName $testName -result NotRun -detail $notRunReason
    }
    
    try
    {
        $properties = Retrieve-AdfsProperties
        if ($properties.AutoCertificateRollover -and ($certificateType -eq "Token-Decrypting" -or $certificateType -eq "Token-Signing"))
        {
            return Create-CertificateCheckResult -certCheckResult $certHasPrivateKey -testName $testName -result NotRun -detail "Check Skipped when AutoCertificateRollover is enabled"
        }    
        
        #special consideration to the corner case where auto certificate rollover was on, then turned off, leaving behind some certificates in the CU\MY store
        #in which case, we cannot ascertain whether the private key is present or not
        if ($storeLocation -eq "CurrentUser")
        {
            return Create-CertificateCheckResult -certCheckResult $certHasPrivateKey -testName $testName -result NotRun -detail "Check Skipped because the certificate is in the CU\MY store"
        }   

        if ($certHasPrivateKey.HasPrivateKey)
        {
            return Create-CertificateCheckResult -certCheckResult $certHasPrivateKey -testName $testName -result Pass
        }
        else
        {
            $tp = $certHasPrivateKey.Thumbprint
            $detail = "$certificateType certificate with thumbprint $tp does not have a private key."
            return Create-CertificateCheckResult -certCheckResult $certHasPrivateKey -testName $testName -result Fail -detail $detail 
        }
    }
    catch [Exception]
    {
        return Create-NotRunExceptionTestResult $testName $_.Exception.Message
    }
}

function Test-CertificateSelfSigned
{
    param (
        [System.Security.Cryptography.X509Certificates.X509Certificate2] 
        $certSelfSigned,
        [string]
        $certificateType,
        [bool]
        $isPrimary = $false,
        [string]
        $notRunReason
    )
    
    $checkName = "IsSelfSigned"
    
    $testName = Create-CertCheckName -certType $certificateType -checkName $checkName -isPrimary $isPrimary
    
    if (-not $certSelfSigned -and [String]::IsNullOrEmpty($notRunReason))
    {
        $notRunReason = "Certificate object is null."
    }
    
    if (-not [String]::IsNullOrEmpty($notRunReason))
    {
        return Create-CertificateCheckResult -certCheckResult $null -testName $testName -result NotRun -detail $notRunReason
    }
    
    try
    {
        $properties = Retrieve-AdfsProperties
        if ($properties.AutoCertificateRollover -and ($certificateType -eq "Token-Decrypting" -or $certificateType -eq "Token-Signing"))
        {
            return Create-CertificateCheckResult -certCheckResult $certSelfSigned -testName $testName -result NotRun -detail "Check Skipped when AutoCertificateRollover is enabled"
        }
        if (Verify-IsCertSelfSigned $certSelfSigned)
        {
            $tp = $certSelfSigned.Thumbprint
            $detail = "$certificateType certificate with thumbprint $tp is self-signed."
            return Create-CertificateCheckResult -certCheckResult $certSelfSigned -testName $testName -result Fail -detail $detail 
        }
        else
        {
            return Create-CertificateCheckResult -certCheckResult $certSelfSigned -testName $testName -result Pass
        }
    }
    catch [Exception]
    {
        return Create-NotRunExceptionTestResult $testName $_.Exception.Message
    }
}

function Test-CertificateCRL
{
    param (
        [System.Security.Cryptography.X509Certificates.X509Certificate2] 
        $certCrl,
        [string]
        $certificateType,
        [bool]
        $isPrimary = $false,
        [string]
        $notRunReason
    )
    
    $checkName = "Revoked"
    $chainStatusKey = "ChainStatus"
    
    $testName = Create-CertCheckName -certType $certificateType -checkName $checkName -isPrimary $isPrimary
    
    if (-not $certCrl -and [String]::IsNullOrEmpty($notRunReason))
    {
        $notRunReason = "Certificate object is null."
    }
    
    if (-not [String]::IsNullOrEmpty($notRunReason))
    {
        return Create-CertificateCheckResult -certCheckResult $null -testName $testName -result NotRun -detail $notRunReason
    }
    
    try
    {
        $crlResult = VerifyCertificateCRL -certCrl $certCrl 
        $passFail = [ResultType]::Pass
        if (($crlResult.ChainBuildResult -eq $false) -and ($crlResult.IsSelfSigned -eq $false))
        {
            $passFail = [ResultType]::Fail            
        }
        $testResult = Create-CertificateCheckResult -certCheckResult $certCrl -testName $testName -result $passFail
        $testDetail = "Thumbprint: " + $crlResult.Thumbprint + "`n"
        
        $testResult.Output.Add($chainStatusKey, "NONE")
        if ($crlResult.ChainStatus)
        {
            $testResult.Output.Set_Item($chainStatusKey, $crlResult.ChainStatus)
            foreach($chainStatus in $crlResult.ChainStatus)
            {
                $testDetail = $testDetail + $chainStatus.Status + "-" + $chainStatus.StatusInformation + [System.Environment]::NewLine
            }
        }
        
        $testResult.Detail = $testDetail
        return $testResult
    }
    catch [Exception]
    {
        return Create-NotRunExceptionTestResult $testName $_.Exception.Message
    }
}