lib/New-TMConsoleCertificate.ps1

# $Cert = New-SelfSignedCertificate -Subject 'tony.baker'

function New-TMConsoleCertificate {
    param (
    )

    ## Perform Windows Setup
    if ($IsWindows) {

        ## Only admins can create certificates
        if (-Not (Test-IsAdmin)) {
            throw 'Creating a certificate requires administrative permission.'
        }

        ## Provide naming details for the certificate
        $SubjectName = $env:COMPUTERNAME
    
        ## Create File Path variables
        $OutFolder = "$($ENV:APPDATA)\tmconsole\certificates"
        Test-FolderPath -FolderPath $OutFolder
        
        ## Remove Existing Certificates
        Get-ChildItem -Path $OutFolder -Recurse -Force | Remove-Item -Force -Recurse
        
        $OutServerKeyPath = Join-Path $OutFolder 'TMConsole.key'
        $OutCertificatePath = Join-Path $OutFolder 'TMConsole.pem'
        $TempDERKeyPath = Join-Path $OutFolder 'TMConsole.der'
        
        ## Create the Self Signed Certificate
        $CertSettingsSplat = @{
            DnsName           = $SubjectName 
            CertStorelocation = 'Cert:\LocalMachine\My'
            KeyLength         = 2048  
            KeyFriendlyName   = $SubjectName 
            KeyAlgorithm      = 'RSA'
            KeyUsageProperty  = 'All'
            Provider          = 'Microsoft Enhanced RSA and AES Cryptographic Provider'
            FriendlyName      = $SubjectName
            HashAlgorithm     = 'Sha256'
            KeyExportPolicy   = 'Exportable'
            Keyspec           = 'KeyExchange'
            NotAfter          = (Get-Date).AddYears(2)
        }
        try {
            Write-Verbose "New Cert Settings: $CertSettingsSplat"
            $TempCert = New-SelfSignedCertificate @CertSettingsSplat
            $NewCert = Get-ChildItem "Cert:\LocalMachine\My\$($TempCert.Thumbprint)"
        }
        catch {
            throw "Failed to create certificate: $_"
        }
    
        if (-Not $NewCert.PrivateKey) {
            throw "There was an error creating the TLS Certificate for TMConsole. No Private Key was available for export."
        }

        ## Convert the Certificate to an RSA Certificate format to export the Private Key
        $RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($NewCert);
        $RsaPrivateKeyBytesB64 = [Convert]::ToBase64String($RSACng.ExportRsaPrivateKey(), "InsertLineBreaks")
    
        ## Create the output string
        $PrivateKeyString = "-----BEGIN RSA PRIVATE KEY-----`r`n"
        $PrivateKeyString += $RsaPrivateKeyBytesB64
        $PrivateKeyString += "`r`n-----END RSA PRIVATE KEY-----"

        ## Write the output string to the key file
        $PrivateKeyString | Set-Content $OutServerKeyPath -Force
    
        ## Convert the certificate to get a Public Certificate
        Export-Certificate -cert $NewCert -FilePath $TempDERKeyPath -type CERT -Force | Out-Null
        certutil -encode $TempDERKeyPath $OutCertificatePath | Out-Null
        Remove-Item -Path $TempDERKeyPath

        ## Import this certificate to the user's trusted root certificates
        try {

            Import-Certificate -FilePath $OutCertificatePath -CertStoreLocation "cert:\LocalMachine\Root" -Confirm:$False | Out-Null
        }
        catch {
            throw "Unable to import certificate to Local Machine Root store: $_"
        }
    }
    ## Perform Mac Setup
    if ($IsMacOS) {

        ## Ensure OpenSSL is installed
        if (-Not (Test-Path -Path '/usr/bin/openssl')) {
            throw 'Open SSL is not installed'
        }

        ## Provide naming details for the certificate
        $SubjectName = & hostname -s 
        # $SubjectName = $SystemHostName + '.local'

        ## Create File Path variables
        $CertificatesPath = Join-Path '/' 'Users' $env:USER 'Library' 'Application Support' 'tmconsole' 'certificates'
        
        ## Remove existing certificates
        Get-ChildItem -Path $CertificatesPath -File | Where-Object {$_.Name -like 'TMConsole*'} | Remove-Item -Force
        
        ## Create appropriate file paths
        $CAKeyPath = Join-Path $CertificatesPath 'TMConsoleCA.key'
        $CACSRPath = Join-Path $CertificatesPath 'TMConsoleCA.csr'
        $CACertPath = Join-Path $CertificatesPath 'TMConsoleCA.crt'
        $CAPemPath = Join-Path $CertificatesPath 'TMConsoleCA.pem'

        $AppKeyPath = Join-Path $CertificatesPath 'TMConsole.key'
        $AppCsrPath = Join-Path $CertificatesPath 'TMConsole.csr'
        $AppCertPath = Join-Path $CertificatesPath 'TMConsole.crt'
        $AppPemPath = Join-Path $CertificatesPath 'TMConsole.pem'

        ##
        ## Generate a CA Certificate
        ##
        $Country = 'US'
        $State = 'MA'
        $Location = 'Boston'
        $Organization = 'TransitionManager'
        $OU = 'TMConsole'
        $SupportEmail = 'support@transitionmanager.com'

        ## Compile the Certificate Subject String
        $BaseSubjectString = "/C=$Country"
        $BaseSubjectString += "/ST=$State"
        $BaseSubjectString += "/L=$Location"
        $BaseSubjectString += "/O=$Organization"
        $BaseSubjectString += "/OU=$OU"
        $BaseSubjectString += "/emailAddress=$SupportEmail"
        
        ## Compile the X509 Subject String
        $CaSubjectString = "/CN=TMConsoleRootCA" + $BaseSubjectString
        openssl genrsa -out $CAKeyPath 2048
        openssl req -sha256 -new -key $CAKeyPath -out $CACSRPath -subj $CaSubjectString
        openssl req -x509 -days 1825 -key $CAKeyPath -in $CACSRPath -out $CACertPath
        cat $CACertPath $CAKeyPath > $CAPemPath
        
        ##
        ## Generate a self-signed certificate
        ##
        
        ## Create an RSA Keypair for the Application Certificate
        $AppSubjectString = "/CN=$SubjectName" + $BaseSubjectString
        openssl genrsa -out $AppKeyPath 2048
        openssl req -sha256 -new -key $AppKeyPath -out $AppCsrPath -subj $AppSubjectString
        
        ## Sign the CSR with the CA key producing the Server Certificate
        openssl req -x509 -sha256 -days 1095 -in $AppCsrPath -key $CaKeyPath `
            -passin pass:tmconsole -out $AppCertPath -nodes `
            -config $OpenSslSettings -extensions 'v3_req' 
        
        cat $CACertPath $AppCertPath $AppKeyPath > $AppPemPath
        
        ## Add the Certificate to the User's Trusted Store (-d Admin Store)
        sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $CaCertPath
        sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $AppCertPath
        
        ## Remove temporary files
        Remove-Item $CaCsrPath -Force
        Remove-Item $AppCsrPath -Force
    }
}