Skip Ribbon Commands
Skip to main content

Ondrej Sevecek's English Pages

:

Engineering and troubleshooting by Directory Master!
MCM: Directory

Quick Launch

Ondrej Sevecek's English Pages > Posts > Error with RDP and the autoenrollment archiving still valid certificates
December 03
Error with RDP and the autoenrollment archiving still valid certificates

Today, I have run again to the common problem with the PKI autoenrollment technology which automatically renews certificates which are based on certificate templates. It was in combination with Remote Desktop Services (RDP) and their domain based, automatically issued internal certificate.

In a customer environment, they use their own intenal CA (based on AD CS) and issue RDP server certificates automatically to all RDP servers. In fact, they issue the certificates to all machines as most machine can be accessed remotely over RDP either by their own employees or some administrators staff.

They use the Remote Desktop Authentication EKU certificates (OID 1.3.6.1.4.1.311.54.1.2). The Remote Desktop Configuration service (SessionEnv) running on all the RDP servers (in fact, most of them are workstations) automatically enrolls for the the certificate if none is available. That works correctly. But it does not use the autoenrollment technology actually. It just requests the certificate "automatically". I say "automatically" because it does not need the Autoenroll permission on the certificate template. It makes do with the Enroll permission only, just like you were enrolling for a certificate manually. So rather to call it semi-automatically, because it does not require user action, but it also does not require the autoenrollment process.

Note - it is just the same behavior that you can observe with EFS.

And here comes the problem. They have autoenrollment technology enabled as well. And it also renews the certificates itself. What is worse, it does the renewal at some point prior the certificate expiration - typically at its 80% time of expiration. What the worst thing here is, is that the autoenrollment process also archives the existing, although still valid, certificate.

And it confuses the Remote Desktop Configuration service (SessionEnv) completelly. If it sees a yet valid certificate, although it is already archived, it ignores the archive bit on the certificate and tries to use it. But, because the certificate is archived, it cannot be used by the SChannel SSP and the TLS/SSL connection fails with the following errors:

Remote Desktop Connection - the connection cannot proceed because
authentication is not enabled and the remote computer requires that
authentication be enabled to connect.
The identity of the remote computer cannot be verified. This problem
can occur if the remote computer is running a version of Windows that
is earlier than Windows Vista, or if the remote computer is not
configured to support server authentication.
Log: System
Source: Schannel
Event Id: 36870
Event level: Error
A fatal error occurred when attempting to access the SSL server credential
private key. The error code returned from the cryptographic module
is 0x8009030d. The internal error state is 10001.

Even if you yourself want to see the archived certificates on the server, you must enable it in the Certificates MMC console, in its View - Options - Archived certificates. Normally, you do not see archived certificates in the console by default. So no magic the SessionEnv service (or rather to say the SChannel SSP which performs the TLS actually) does not work correctly with such a confused setup.

How to solve it? You must either delete the archived certificates and restart the Remote Desktop Configuration service (SessionEnv), or you must replace the server certificate with the Remote Desktop Session Host Configuration console or with PowerShell.

Comments

Re: Error with RDP and the autoenrollment archiving still valid certificates

I had the same error. I reselect certificate in RDP-Tcp properties and replace inheritated permissions to C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
 on 23/12/2013 14:24

Re: Error with RDP and the autoenrollment archiving still valid certificates

I had the same error. I reselect certificate in RDP-Tcp properties and replace inheritated permissions to C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
 on 23/12/2013 14:32

Re: Error with RDP and the autoenrollment archiving still valid certificates

solution in the form of a PowerShell automatic deletion of the archived Server Authentication certificates. Unfortunately in Czech, but the script is so simple you will not need a translation hopefully.

http://www.sevecek.com/Lists/Posts/Post.aspx?ID=396
 on 03/03/2014 19:52

TIA

Thanks for the article - you have saved my life!
 on 07/03/2015 02:12

Re: Error with RDP and the autoenrollment archiving still valid certificates

Is there a recommended way to configure the certs so this doesn't happen?  I actually don't have autoenroll permissions configured on my cert template but this exact scenario is happening for me.  Interestingly, only the server 2008 R2 servers are complaining.  The 2012 and 2012 R2 servers do not have issues.
 on 21/05/2015 19:22

Script to fix it on all domain-joined servers

Thank you! We had this problem and didn't notice for about a month, so needless to say we had a lot of certificates to clean up across a lot of servers. Here's a script I put together based on your work that fixed the issue on all Windows servers in our AD domain, in case anyone else needs it. I filtered the certificates a little differently than you did in http://www.sevecek.com/Lists/Posts/Post.aspx?ID=396 because I couldn't use the -Eku parameter on some of our older servers.

# Remove all archived certs in the LocalMachine store across domain servers where the subject is CN=servername...
$Servers = Get-ADComputer -Properties * -Filter {enabled -eq $true -and operatingsystem -like "*server*"}
$ServerNum = 1
$Servers|%{
    "[$ServerNum/$($Servers.Count)]:"
    " 1/3 Removing archived certs from local machine store..."
    Invoke-Command -ComputerName $_.Name {gci -Recurse 'Cert:\LocalMachine\My' -force | where {$_.archived -eq $true} | where {$_.subject -like "CN=$($_.Name)*"} | Remove-Item -force }
    " 2/3 Stopping SessionEnv..."
    Invoke-Command -ComputerName $_.Name {sc.exe stop sessionenv}
    " 3/3 Restarting SessionEnv..."
    Invoke-Command -ComputerName $_.Name {sc.exe start sessionenv}
    $ServerNum++
}
 on 18/07/2015 01:03

Script to fix it on all domain-joined servers

Thank you! We had this problem and didn't notice for about a month, so needless to say we had a lot of certificates to clean up across a lot of servers. Here's a script I put together based on your work that fixed the issue on all Windows servers in our AD domain, in case anyone else needs it. I filtered the certificates a little differently than you did in http://www.sevecek.com/Lists/Posts/Post.aspx?ID=396 because I couldn't use the -Eku parameter on some of our older servers.

# Remove all archived certs in the LocalMachine store across domain servers where the subject is CN=servername...
$Servers = Get-ADComputer -Properties * -Filter {enabled -eq $true -and operatingsystem -like "*server*"}
$ServerNum = 1
$Servers|%{
    "[$ServerNum/$($Servers.Count)]:"
    " 1/3 Removing archived certs from local machine store..."
    Invoke-Command -ComputerName $_.Name {gci -Recurse 'Cert:\LocalMachine\My' -force | where {$_.archived -eq $true} | where {$_.subject -like "CN=$($_.Name)*"} | Remove-Item -force }
    " 2/3 Stopping SessionEnv..."
    Invoke-Command -ComputerName $_.Name {sc.exe stop sessionenv}
    " 3/3 Restarting SessionEnv..."
    Invoke-Command -ComputerName $_.Name {sc.exe start sessionenv}
    $ServerNum++
}
 on 20/07/2015 18:03

Another Solution

The environment I support isn't perfect - Powershell remoting and scripting aren't enabled, and WMI is broken on a number of systems so I'm stuck using PSEXEC and CMD to solve this problem.  I also have some servers with German language, so there's accommodation for that here as well.  Hope this helps someone, and I really hope MS comes up with a solution for this problem!

$SetRDPSSL = @"
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set certFlag=0
set archFlag=0
set xChange=TRUE
for /f "skip=1 usebackq" %%a in (``c:\windows\system32\wbem\wmic.exe /namespace:\\root\cimv2\terminalservices path win32_tsgeneralsetting get sslcertificatesha1hash ^| findstr /r "[^s]"``) do (
  set curTP=%%a
REM echo !curTP!
)
for /f "tokens=* usebackq" %%a in (``c:\windows\system32\certutil.exe -store my``) do (
  set z=%%a
  for /f "tokens=1,2 delims=:" %%a in ("!z!") do (
    set _key=%%a
    set _data=%%b
    if "!_key:~0,4!"=="====" set archFlag=0
    if "!_key:~0,9!"=="Archived!" set archFlag=1
    if "!_key:~0,9!"=="Archivier" set archFlag=1

    if "!_data:~1,12!"=="SecureServer" (
      if !archFlag!==0 set certFlag=1
    )
    set certchk=true
    if not "!_key:~0,15!"=="Cert Hash(sha1)" if not "!_key:~0,15!"=="Zertifikathash(" set certchk=false
    if "!certchk!"=="true" (
      if !certFlag!==1 (
        set certFlag=0
        set newTP=!_data: =!
        if /I NOT "!newTP!"=="!curTP!" (
          set xEligible=TRUE
          c:\windows\system32\wbem\wmic.exe /namespace:\\root\cimv2\terminalservices path win32_tsgeneralsetting set sslcertificatesha1hash="!newTP!"
        )
        for /f "skip=1 usebackq" %%a in (``c:\windows\system32\wbem\wmic.exe /namespace:\\root\cimv2\terminalservices path win32_tsgeneralsetting get sslcertificatesha1hash ^| findstr /r "[^s]"``) do (
          set xTP=%%a
        )
      )
    )
  )
)
for /f "usebackq tokens=*" %%a in (``c:\windows\system32\wbem\wmic.exe os get caption ^| findstr /C:"Microsoft"``) do (
  set xos=%%a
)
if "!xEligible!"=="TRUE" (
  if "!curTP!"=="!xTP!" set xChange=FALSE
)
  
echo %computername%,!xos!,!curTP!,!newTP!,!xTP!,!xEligible!,!xChange!

"@

$date = "{0:yyyyMMdd_HHmmss}" -f (Get-Date)

$servers = Get-ADComputer -filter {(OperatingSystem -like '*2008*' -or OperatingSystem -notlike '*') -and (Enabled -eq $True)} -property Name | ?{$exlist -notcontains $_.name} | Select -expand Name | Sort
$locpath = "c:\windows\temp"
$ScriptPath = Split-Path $script:MyInvocation.MyCommand.Path

$hdrs = @("Server","OS","CurrentThumbprint","NewThumbprint","ChangedThumbprint","Eligible","Pass","Note")
$servers = $servers | ?{$_ -notlike "wd*"}
$servercount = $servers.Count
$Count = 0
$results = $(foreach ($server in $servers) {
  $Count += 1
  Write-Progress -Activity "Checking RDP SSL Status" -Status "Checking $server, $count of $servercount" -percentComplete (($Count / $servercount) * 100)
  $result = "" | select $hdrs
  $result.Server = $server
  $rempath = "\\$server\c$\Windows\Temp"
  if (!$(Try{$(if(Test-Path $rempath -ea stop){$true}Else{$false})}Catch{$false})) {
    $result.NOTE = "INACCESSIBLE"
  } Else {
    Do {
      $tempfile = "$((([System.IO.Path]::GetTempFileName() -split "\\")[-1] -split "\.")[0])`.cmd"
    } Until (!(Test-Path "$rempath\$tempfile"))
    Try {
      $setRDPSSL | Out-File "$rempath\$tempfile" -encoding ascii
      $x = $null
      $x = (invoke-expression '& psexec /s \\$server cmd /c "$locpath\$tempfile" 2>c:\windows\temp\stderr.txt') -join "" -replace "`r" -split ","
      if (!($LastExitCode -eq 0)) {
        $result.NOTE = "PSEXEC:  $LastExitCode"
      } Else {
        if ($x) {
          $result.Server = ($x[0] -split "\.")[-1]
          $result.OS = $x[1] -replace ",",""
          $result.CurrentThumbprint = $x[2]
          $result.NewThumbprint = $x[3]
          $result.ChangedThumbprint = $x[4]
          $result.Eligible = $x[5]
          $result.Pass = $x[6]
        } Else {
          $result.NOTE = "No Script Output"
        }
      }
      del "$rempath\$tempfile"
    } Catch {
      $result.Note = $Error[0].Exception.Message
    }
  }
  $result
}) | select $hdrs | export-CSV "$scriptpath\Update_RDP-SSLCert_Results_$date`.csv" -notype
 on 09/10/2015 14:42

Real Solution

I found this recently, although it's an old issue.  This update can be run silently with
wusa <path and name of  msu> /quiet /norestart

after stopping SessionEnv and TermService services.  Restart the services and the problem is solved.
 on 13/10/2015 16:32

Thank you so very much for this solution!!

It just started happening and it was driving me crazy till I found your article. Thank you once again!!!!
 on 04/02/2016 05:11
1 - 10Next

Add Comment

Title


You do not need to provide any value this column. It will automatically fill with the name of the article itself.

Author *


Body *


Type the year of the start of the WW1 *


This simple antispam field seems to work well. Just put here the number.

Attachments