Common/SSL/SSL-Module.psm1

Import-Module "$PSScriptRoot\..\Run-Pipelines.psm1" -Force
$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 = $global:Configuration.ssl.custom.clientCert
    if ([string]::IsNullOrEmpty($clientCert)) {
        $clientCert = "$($Prefix)_SitecoreClient_SAF"
    }

    return $clientCert
}

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

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

    return $serverCert
}

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

    $serverCert = $global:Configuration.ssl.custom.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 "Removing $CertName SSL Certificate from $Store store done."
}

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

    CleanCertStore -CertName $RootCertName -Store "CurrentUser"

    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"
    
    Write-Output "Generating '$ServerCertName' Certificate started..."
    New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -Signer $rootCert -Subject $ServerCertName -DnsName $Hostnames -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"

    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..."
    }

    $securePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force

    $dir = Get-Location

    $pfxPath = "$dir\$PfxName"

    if ($Root.IsPresent) {
        Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation Cert:\LocalMachine\Root -Password $securePassword -Exportable
    }
    else {
        Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation Cert:\LocalMachine\My -Password $securePassword -Exportable
    }
    
    Write-Output "Importing SSL Certificate from $PfxName done."
}

function SetSSLCertsAppPoolsAccess {
    [CmdletBinding()]
    Param(
        [string]$ClientCertName,
        [string[]]$Hostnames
    )

    Write-Output "Set SSL Certificates AppPools access started..."
    
    foreach ($hostName in $Hostnames) {
        if (Test-Path "IIS:\AppPools\$hostName") {
            Write-Output "Granting access - $hostName IIS AppPool..."
            $params = @{
                Path         = "$PSScriptRoot\set-sslcerts-access.json"
                XConnectCert = $ClientCertName
                AppPoolName  = $hostName
            }
            Install-SitecoreConfiguration @params
        }
    }

    Write-Output "Set SSL Certificates AppPools access done."
}

function StartSSLCertsPipeline {
    [CmdletBinding()]
    Param
    (
        [string]$Pipeline,
        [switch]$Force
    )
    
    RunSteps -Pipeline $Pipeline -Force:$Force
}

Export-ModuleMember -Function "StartSSLCertsPipeline"
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 "SetSSLCertsAppPoolsAccess"
Export-ModuleMember -Function "IsCertInstalled"