Core/SSL-Module.psm1

$ErrorActionPreference = "Stop"

function IsCertInstalled {
    [CmdletBinding()]
    Param(
        [string]$Cert
    )

    try {
        $certItem = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Subject -match $Cert }
        if ($null -eq $certItem) {
            $certItem = Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -match $Cert }
        }

        return !($null -eq $certItem)
    }
    catch {
        Write-Warning "Exception occurred while looking for SSLCert."
        $exception = $_.Exception | Format-List -Force | Out-String
        Write-Warning $exception
        return $false
    }
}

function BuildSitecoreRootCertName {
    [CmdletBinding()]
    Param(
        [string]$Prefix
    )

    $crt = "$($Prefix)_SitecoreRoot_SAF"
    return $crt
}

function BuildSolrRootCertName {
    [CmdletBinding()]
    Param(
        [string]$Prefix
    )

    $crt = "$($Prefix)_SolrRoot_SAF"
    return $crt
}

function BuildSitecoreClientCertName {
    [CmdletBinding()]
    Param
    (
        [string]$Prefix
    )

    $clientCert = $SAFConfiguration.ssl.clientCert
    if ([string]::IsNullOrEmpty($clientCert)) {
        $clientCert = "$($Prefix)_SitecoreClient_SAF"
    }

    return $clientCert
}

function BuildSolrServerCertName {
    [CmdletBinding()]
    Param
    (
        [string]$Prefix
    )

    $serverCert = $SAFConfiguration.ssl.serverCert
    if ([string]::IsNullOrEmpty($serverCert)) {
        $serverCert = "$($Prefix)_SolrServer_SAF"
    }

    return $serverCert
}

function BuildSitecoreServerCertName {
    [CmdletBinding()]
    Param
    (
        [string]$Prefix
    )

    $serverCert = $SAFConfiguration.ssl.serverCert
    if ([string]::IsNullOrEmpty($serverCert)) {
        $serverCert = "$($Prefix)_SitecoreServer_SAF"
    }
    
    return $serverCert
}

function CleanCertStore {
    [CmdletBinding()]
    Param(
        [string]$CertName,
        [string]$Store
    )
   
    Write-Output "Removing $CertName SSL Certificate from $Store store..."
    Get-ChildItem Cert:\$Store\Root | Where-Object { $_.Subject -match $CertName } | Remove-Item
    Get-ChildItem Cert:\$Store\My | Where-Object { $_.Subject -match $CertName } | Remove-Item
    Write-Output "Done."
}

function GenerateRootCert {
    [CmdletBinding()]
    Param(
        [string]$RootCertName,
        [int]$ValidYears = 10
    )

    CleanCertStore -CertName $RootCertName -Store "CurrentUser"
    CleanCertStore -CertName $RootCertName -Store "LocalMachine"

    Write-Output "Generating '$RootCertName' Root CA Certificate started..."
    New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -DnsName "$RootCertName" -KeyusageProperty All -KeyUsage DigitalSignature, CertSign -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears($ValidYears) -FriendlyName $RootCertName
    Write-Output "Generating '$RootCertName' Root CA Certificate done."
}

function GenerateServerCert {
    [CmdletBinding()]
    Param(
        [string]$RootCertName,
        [string]$ServerCertName,
        [string[]]$Hostnames,
        [int]$ValidYears = 10
    )

    $rootCert = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $RootCertName }
    if ($null -eq $rootCert) {
        throw "Can not find SSL Root CA Certificate with name '$RootCertName'..."
    }

    CleanCertStore -CertName $ServerCertName -Store "CurrentUser"
    CleanCertStore -CertName $ServerCertName -Store "LocalMachine"

    $hostNamesWithWildCards = @()
    foreach ($hostName in $Hostnames) {
        $hostNamesWithWildCards += $hostName
        $hostNamesWithWildCards += "*.$hostName"
    }
    
    Write-Output "Generating '$ServerCertName' Certificate started..."
    New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -Signer $rootCert -Subject $ServerCertName -DnsName $hostNamesWithWildCards -KeyusageProperty All -KeyUsage KeyEncipherment, DigitalSignature -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears($ValidYears) -FriendlyName $ServerCertName
    Write-Output "Generating '$ServerCertName' Certificate done."
}

function GenerateClientCert {
    [CmdletBinding()]
    Param(
        [string]$RootCertName,
        [string]$ClientCertName,
        [string[]]$Hostnames,
        [int]$ValidYears = 10
    )

    $rootCert = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $RootCertName }
    if ($null -eq $rootCert) {
        throw "Can not find SSL Root CA Certificate with name '$RootCertName'..."
    }

    CleanCertStore -CertName $ClientCertName -Store "CurrentUser"
    CleanCertStore -CertName $ClientCertName -Store "LocalMachine"

    Write-Output "Generating '$ClientCertName' Certificate started..."
    New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -Signer $rootCert -Subject $ClientCertName -DnsName $Hostnames -KeyusageProperty All -KeyUsage KeyEncipherment, DigitalSignature -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears($ValidYears) -FriendlyName $ClientCertName
    Write-Output "Generating '$ClientCertName' Certificate done."
}

function ExportCert {
    [CmdletBinding()]
    Param(
        [string]$CertName,
        [string]$PfxName,
        [string]$ExportPath,
        [string]$Password
    )

    # Export PFX certificates along with private key
    $certDestPath = Join-Path -Path $ExportPath -ChildPath $PfxName
    if (Test-Path $certDestPath) {
        Remove-Item $certDestPath -Force | Out-Null
    }
   
    $securePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force

    Write-Output "Exporting '$CertName' SSL cetificate started..."
    Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -match $CertName } | Export-PfxCertificate -FilePath $certDestPath -Password $securePassword
    Write-Output "Exporting '$CertName' SSL cetificate done."
}

function SSLCertExistsInCurrentDir {
    [CmdletBinding()]
    Param(
        [string]$PfxName
    )

    $dir = Get-Location
    if (!(Test-Path "$dir\$PfxName")) {
        return $false
    }
    return $true
}

function ImportCert {
    [CmdletBinding()]
    Param
    (
        [string]$PfxName,
        [string]$Password,
        [switch]$Root
    )

    Write-Output "Importing SSL Certificate from $PfxName started..."

    if (!(SSLCertExistsInCurrentDir -PfxName $PfxName)) {
        throw "Please, provide $PfxName SSL Certificates for import..."
    }

    $dir = Get-Location
    $pfxPath = "$dir\$PfxName"

    if ($Root.IsPresent) {
        certutil -user -p $Password -enterprise -importpfx root $pfxPath
    }
    else {
        certutil -p $Password -importpfx $pfxPath
    }
    
    Write-Output "Importing SSL Certificate from $PfxName done."
}

function SetAppPoolAccessToSSLCert {
    [CmdletBinding()]
    Param(
        [string]$SSLCertName,
        [string]$AppPoolName
    )

    Write-Output "Set '$AppPoolName' AppPool access to '$SSLCertName' SSL certificate started..."
   
    $appPool = Get-IISAppPool $AppPoolName
    if ($null -ne $appPool) {
        $params = @{
            Path        = "$PSScriptRoot\set-sslcert-access.json"
            SSLCertName = $SSLCertName
            AppPoolName = $AppPoolName
        }
        Install-SitecoreConfiguration @params
        RestartAppPool -AppPoolName $AppPoolName
    }
    
    Write-Output "Set '$AppPoolName' AppPool access to '$SSLCertName' SSL certificate done."
}

function NewSSLCerts {
    [CmdletBinding()]
    Param
    (
        [switch]$Force
    )
    
    RunPipeline -DefinitionFile $SAFConfigureSSLPipelines -Name "newSSLCerts" -Force:$Force
}

Export-ModuleMember -Function "NewSSLCerts"
Export-ModuleMember -Function "GenerateRootCert"
Export-ModuleMember -Function "GenerateServerCert"
Export-ModuleMember -Function "GenerateClientCert"
Export-ModuleMember -Function "ExportCert"
Export-ModuleMember -Function "BuildSitecoreClientCertName"
Export-ModuleMember -Function "BuildSitecoreServerCertName"
Export-ModuleMember -Function "BuildSitecoreRootCertName"
Export-ModuleMember -Function "BuildSolrRootCertName"
Export-ModuleMember -Function "BuildSolrServerCertName"
Export-ModuleMember -Function "CleanCertStore"
Export-ModuleMember -Function "ImportCert"
Export-ModuleMember -Function "SetAppPoolAccessToSSLCert"
Export-ModuleMember -Function "IsCertInstalled"