Site icon Franky's Web

Sophos UTM: Export WAF certificate using PowerShell (Exchange version)

In this article I have already described how the Sophos UTM certificate can be exported via REST API. A few people have now reported that an automatic export and import for Exchange Server is interesting. I have therefore extended the script and successfully tested the export and import with Exchange Server 2016.

Here is the customized version for the automatic import for Exchange Server 2016:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#Requires -RunAsAdministrator
param(
    [Parameters(Position=0, Mandatory=$true)]
        $UTMAddress = "utm.domain.local",
    [Parameters(Position=1, Mandatory=$true)]
        [string]$UTMApiToken = "xxXXxxxxXXXXXXXXXX",
    [Parameters(Position=2, Mandatory=$true)]
        [string]$CertREF = "REF_0815abcd",
    [Parameters(Position=3, Mandatory=$false)]
        [string]$OpenSSLPath = "C:\Program Files (x86)\OpenSSL\bin\openssl.exe",
    [Parameters(Position=4, Mandatory=$false)]
        [string]$PFXFilePath = $PSScriptRoot
    )
 
#Set TLS Settings (Only TSLv1.1 and TLSv1.2)
try
    {
        write-warning "Changing PowerShell TLS settings"
        [System.Net.ServicePointManager]::SecurityProtocol = @("Tls12","Tls11","Tls")
    }
catch
    {
        write-error "Can't change PowerShell TLS settings: $Error[0]"
    }
 
#Build Credentials
try
    {
        Write-Warning "Building UTM Rest API Creds"
        $securePassword = ConvertTo-SecureString $UTMApiToken -AsPlainText -Force
        $credential = New-Object System.Management.Automation.PSCredential("token", $securePassword)
    }
catch
    {
        write-error "Error building UTM creds: $Error[0]"
        exit
    }
 
#UTM API Call to get certificate and private key
try
    {
        Write-Warning "Getting Cert from UTM REST API"
        $UTMAPICall = "https://$UTMAddress" + ":4444/api/objects/ca/host_key_cert/$CertREF"
        $UTMCertResponse = Invoke-RestMethod -Method GET -Uri $UTMAPICall -Credential $credential
    }
catch
    {
        write-error "Error getting certificate from UTM: $Error[0]"
        exit
    }
 
#Write private key and certificate to temp files
try
    {
        Write-Warning "Writing cert TMP files"
        $TempCertFile = "$env:temp\" + $CertREF + ".cer"
        $TempKeyFile = "$env:temp\" $CertREF + ".key"
        $UTMCertResponse.certificate | set-content $TempCertFile
        $UTMCertResponse.key | set-content $TempKeyFile
    }
catch
    {
        write-error "Error writing temp files: $Error[0]"
        exit
    }
    
#Build PFX File from certificate and key
try
    {
        Write-Warning "Convert UTM Cert and Key to PKCS12"
        $PFXFileNameAndPath = "$PFXFilePath" + "\" + "$CertREF" + ".pfx"
        . $OpenSSLPath pkcs12 -export -in $TempCertFile -inkey $TempKeyFile -out $PFXFileNameAndPath -password pass:$UTMApiToken
        remove-item $TempCertFile -force
        remove-item $TempKeyFile -force
    }
catch
    {
        write-error "Error building PFX File: $Error[0]"
    }
 
#Get UTM certs serial number
try
    {
        $UTMCertSerial = $UTMCertResponse.certificate.split(" ")[35].ToUpper().Replace(":","").Trim()
        Write-Warning "UTM Cert Serial: $UTMCertSerial"
    }
catch
    {
        write-error "Can't find serial number of UTMs certificate: $Error[0]"
        exit
    }
    
#Get current Exchange Server certificate
try
    {
        write-warning "Get current Exchange Server Certificate"
        Import modules -Name WebAdministration
        Add-PSSnapin Microsoft.Exchange*
        $AllIISCerts = Get-ChildItem IIS:SSLBindings
        foreach ($IISCert in $AllIISCerts)
         {
          if ($IISCert.sites.value -match "Default Web Site") {$IISThumbprint = $IISCert.Thumbprint}
         }
        $CurrentExchangeCert = Get-ExchangeCertificate -Thumbprint $IISThumbprint
        $CurrentExchangeCertSerial = $CurrentExchangeCert.SerialNumber
        write-warning "Exchange Cert Serial: $CurrentExchangeCertSerial"
    }
catch
    {
        write-error "Can't find current Exchange certificate: $Error[0]"
        exit
    }
    
#Test if current Exchange Cert matches UTM Cert
try
    {
        if ($CurrentExchangeCertSerial -eq $UTMCertSerial)
         {
            Write-Warning "Exchange certificate matches UTM certificate: Nothing to do!"
            $ExchangeCertChangeRequierd = $false
         }
        else
         {
            write-warning "UTM Cert dosen't match Exchange certificate!"
            $ExchangeCertChangeRequierd = $true
         }
    }
catch
    {
        write-error "Don't know if cert change is requierd: $Error[0]"
        exit
    }
 
#If needed: lets try to change the Exchange Server certificate
if ($ExchangeCertChangeRequierd -eq $true)
    {
     try
        {
            Write-Warning "Let's try to change the certificate"
            $CertFilePath = "\\" + $env:computername + "\" + $PFXFileNameAndPath.Replace(":","$")
            $ImportCert = Import-ExchangeCertificate -FileName $CertFilePath -Password $securePassword -PrivateKeyExportable:$true -FriendlyName "$CertREF"
            $EnableCert = Get-ExchangeCertificate | where {$_.SerialNumber -eq $UTMCertSerial} | Enable-ExchangeCertificate -Services POP,IMAP,SMTP,IIS -force
            $ChangeSuccessfull = $true
            write-warning "Change Sucessfull: $ChangeSuccessfull"
        }
     catch
        {
            write-error "Can't change certificate: $Error[0]"
            exit
        }
    }
if ($ExchangeCertChangeRequierd -eq $false)
    {
     Write-Information "No certificate change needed"
     exit
    }
    
#Remove the old Exchange server certificate if change was successfull
if ($ChangeSuccessfull -eq $true)
    {
     try
        {
            Write-Warning "Removing old certificate"
            $RemoveCert = Remove-ExchangeCertificate -Thumbprint $IISThumbprint -Confirm:$false
        }
    catch
        {
            write-error "Can't remove old certificate: $Error[0]"
            exit
        }
    }
 
   

The script can also be downloaded directly here as a PS1 file:

This script can be executed directly on the Exchange Server. It is important that the script is started with administrator rights. Of course, the user must also have the appropriate Exchange permissions to assign the certificate.

The script can be called up as follows:

1
.\Get-SophosUTMCertificate.ps1 -UTMAddress utm.domain.local -UTMApiToken "UTMRESTAPIKEY" -CertREF "REF_XXXXXXXXXX" -OpenSSLPath "C:\Program Files (x86)\OpenSSL\bin\openssl.exe"

Here are two runs of the script. During the first run, it was determined that the certificate of the UTM and the Exchange server are different, so the UTM certificate was installed on the Exchange server. In the second run, the UTM certificate corresponds to the Exchange certificate, so it does not need to be replaced again:

The script can be created as a task in the task scheduler and executed once a day, for example. If the UTM now renews the Let's Encrypt certificate, the Exchange certificate is also replaced with a maximum delay of one day.

Exit mobile version