Script based Autoenrollment for Windows clients with EJBCA

Script based Autoenrollment is a legacy way of doing autoenrollment and is kept for legacy reasons. Native autoenrollment (above) provides a more seamless experience.

This section will show you how to set up automatic certificate enroll of machines and users in an Windows environment with EJBCA.

Introduction

  • Use mod_auth_kerb on a Apache2 web server proxy to validate the requesters identity using Kerberos.

  • A login VBS-Script creates a certificate request that is sent to the proxy using IE-components.

  • A Servlet protected by the proxy receives the requests and creates a new cert.

  • The new certificate will use information from the request (UPN and CertificateTemplate) and read.

  • information from active directory (CN,DC etc).

  • Autoenrollment should be configurable in the Admin GUI.

Current Status and Known Issues

Current Status

  • Machine enroll on Domain Controller: WORKING

  • DomainController enroll on Domain Controller: WORKING

  • User enroll (Administrator) on Domain Controller: NOT WORKING (Does not trusts ca-server as Intranet, despite GP)

  • Machine enroll on other WS2K3 client: WORKING (not checked in a while)

  • User enroll (Administrator) on other WS2K3 client: NOT WORKING (Does not trusts ca-server as Intranet, despite GP, also complains about untrusted VBS if ran manually)

  • Machine enroll on WinXP client: WORKING

  • User enroll (Administrator) on WinXP client: WORKING

Known Issues

  • SECURITY: The Servlet should verify that e.g. only Users can request User certificates, DCs only DC certs etc.. and other permissions if possible.

  • The enroll scripts always fetches new certificates. They should use the command=status first to see if a new cert is needed.

  • AdminWeb cannot verify admin certificates if non-"/ejbca/" path is used in URL.

  • Autoenroll Servlet doesn't get X-Remote-User if "/ejbca/" path is used in URL.

  • Order of Subject DNs is wrong compared with MS certs..

  • SSL connection to AD has not been tested.

  • Certificates don't have the CertificateTemplate attrib yet.. looks nicer in Certificate MMC snapin..

  • JavaScript "onchange" behaves strangely in IE6. Only activated when the table is clicked, not the checkbox..

  • Creation of EEPs is inefficient due to attempted removal of EEP before each new request.. (Debug-code)

Machines and Software

Domain Controller: dc1.company.local

  • Windows Server 2003 EE patched to SP2

  • Active Directory

  • DNS Server

CA Server: ca-server.company.local

  • Ubuntu 64 Server 7.10

  • Apache2 with modules

  • Kerberos 5

  • Java 1.6u4

  • JBoss 4.2.2.GA

  • EJBCA 3.6 Alpha

  • Apache Ant 1.7.0

Desktop client: client-01.company.local

  • Windows XP Pro SP1 patched to SP2

Install EJBCA

Configure EJBCA not to respond to external web-requests by editing $EJBCA_HOME/conf/web.properties

...
httpsserver.bindaddress.pubhttp=127.0.0.1
httpsserver.bindaddress.pubhttps=127.0.0.1
httpsserver.bindaddress.privhttps=127.0.0.1
...

After installation, go to EJBCA Admin GUI -> System Configuration and configure the autoenrollment settings.

Setting up Kerberos Authentication and Apache

This could probably be done on a Windows server as well, since Apache and Kerberos is supposed to work on that platform too:

$sudo su
#apt-get update
#apt-get install krb5-user apache2 libapache2-mod-auth-kerb
** Skip kerberos config.. we will configure this later **
#cd /etc/apache2/mods-enabled/
#ln -s ../mods-available/proxy.load proxy.load
#ln -s ../mods-available/proxy_ajp.load proxy_ajp.load
#ln -s ../mods-available/proxy_balancer.load proxy_balancer.load
#ln -s ../mods-available/rewrite.load rewrite.load
#ln -s ../mods-available/ssl.load ssl.load
#ln -s ../mods-available/headers.load headers.load

Edit /etc/krb5.conf where dc1.company.local is the DNS-name of the Domain Controller and COMPANY.LOCAL is our domain.

[libdefaults]
default_realm = COMPANY.LOCAL
 
[realms]
COMPANY.LOCAL = {
kdc = dc1.company.local:88
admin_server = dc1.company.local:88
}
 
[domain_realm]
.company.local = COMPANY.LOCAL
company.local = COMPANY.LOCAL
 
[logging]
default = FILE:/var/log/apache2/krb5.log

Edit /etc/network/interfaces and set a static IP address:

...
#iface eth0 inet dhcp
iface eth0 inet static
address 192.168.0.102 # Address of this machine
netmask 255.255.255.0
gateway 192.168.0.101 # In our local network this is the Domain Controller

Use the DC as DNS server in /etc/resolv.conf:

search localdomain
nameserver 192.168.0.101

and restart networking (sudo /etc/init.d/networking restart).

Add "ntdpdate dc1.company.local" to /etc/rc.local or a cron job to make sure the ca-server is syncronized with the Domain Controller.

Create the SSL certificates for the Apache proxy using the same CA as our EJBCA installation and the same subject DN.

$cd $EJBCA_HOME
$bin/ejbca.sh ra addendentity apache-ssl foo123 "CN=ca-server.company.local,O=EJBCA Sample,C=SE" "" ManagementCA "" 1 PEM SERVER
$bin/ejbca.sh ra setclearpwd apache-ssl foo123
$bin/ejbca.sh batch
$ls p12/pem/ca-server.company.local*
p12/pem/ca-server.company.local-CA.pem p12/pem/ca-server.company.local-Key.pem p12/pem/ca-server.company.local.pem

Edit /etc/apache2/sites-enabled/000-default to display an apache proxy front for EJBCA:

NameVirtualHost *:80
<VirtualHost *:80>
DocumentRoot /var/www/
 
# Proxy requests to EJBCA instances (only one on local machine configured)
<Proxy balancer://mycluster-kerb>
BalancerMember ajp://localhost:8009/ejbca/
</Proxy>
ProxyPass / balancer://mycluster-kerb/
 
RewriteEngine On
# Redirect all but the CRL Distribution Point, OCSP and Helthcheck to HTTPS
RewriteCond %{THE_REQUEST} !(/publicweb/webdist/certdist.*cmd=crl|/publicweb/status/)
RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [L,R]
# Treat reqeusts to / and /ejbca/ as the same. Required by EJBCA's Admin Web.
RewriteCond %{THE_REQUEST} /ejbca/
RewriteRule ^/ejbca/(.*)$ /$1 [PT]
 
# Configure log
LogLevel warn
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
 
NameVirtualHost *:443
<VirtualHost *:443>
DocumentRoot /var/www/
 
RewriteEngine On
# Treat reqeusts to / and /ejbca/ as the same. Required by EJBCA's Admin Web.
RewriteCond %{THE_REQUEST} /ejbca/
RewriteRule ^/ejbca/(.*)$ /$1 [PT]
 
# Configure secure SSL for this server using SSL certificate generated by EJBCA
SSLEngine on
SSLCipherSuite HIGH
SSLProtocol all -SSLv2
SSLCertificateFile /home/jboss/ejbca/p12/pem/ca-server.company.local.pem
SSLCertificateKeyFile /home/jboss/ejbca/p12/pem/ca-server.company.local-Key.pem
 
# Require Client SSL certificate for the Admin GUI
<Location /adminweb>
SSLVerifyClient require
SSLVerifyDepth 1
SSLCACertificateFile /home/jboss/ejbca/p12/pem/ca-server.company.local-CA.pem
</Location>
 
# Require Kerberos authentication for the Autoenroll Servlet
<Location /autoenroll>
AuthType Kerberos
Krb5Keytab /etc/apache2/http.keytab
KrbAuthRealms COMPANY.LOCAL
KrbServiceName HTTP
KrbMethodNegotiate on
KrbMethodK5Passwd off
Require valid-user
</Location>
 
# Forward the UPN as variable X-Remote-User
RewriteCond %{IS_SUBREQ} ^false$
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule .* - [E=RU:%1]
RequestHeader set X-Remote-User %{RU}e
 
# Proxy requests to EJBCA instances (only one on local machine configured)
<Proxy balancer://mycluster-kerb>
BalancerMember ajp://localhost:8009/ejbca/
</Proxy>
ProxyPass / balancer://mycluster-kerb/
 
# Configure log
LogLevel warn
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>

Restart apache with "sudo /etc/init.d/apache2 restart"

Install Windows support tools on the Domain Controller (found in %WIN2k3CD%\SUPPORT\TOOLS\SUPTOOLS.msi) to get ktpass.exe. Create a new user "ca-server@company.local" and a strong password e.g not FooBar123 used here. Create a keytab-file "http.keytab" on the Domain Controller:

ktpass.exe -princ HTTP/ca-server.company.local@COMPANY.LOCAL -mapuser ca-server -crypto DES-CBC-MD5 -ptype KRB5_NT_PRINCIPAL -mapop set +desonly -pass FooBar123 -out http.keytab
...
keysize 55 HTTP/ca-server.company.local@COMPANY.LOCAL ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype
0x3 (DES-CBC-MD5) keylength 8 (0x64614c9d256bcd6d)
...

And move the file to ca-server.company.local:/etc/apache2/http.keytab change permissions to be readable only by the apache-process:

$chown root:root /etc/apace2/http.keytab

Verify that the keytab is correct:

$kinit Administrator
$kvno HTTP/ca-server.company.local
$klist -e
** Output here should match the one from ktpass.exe **

Verify that the keytab can be used:

$kdestroy
$sudo kinit -k -t /etc/apache2/http.keytab HTTP/ca-server.company.local
$sudo klist
(You should have received a ticket here if everything is working.)
$sudo kdestroy

Add ca-server.company.local (192.168.1.2) to your Domain Controllers DNS server as a "Host (A)" record.

Set up Enrollment Scripts to Run Automatically

Create a Shared directory on the Domain Controller, C:\Shared with read and exec rights by Everyone:

copy %SYSTEMROOT%\system32\certreq.exe C:\Shared\Autoenroll\
copy %SYSTEMROOT%\system32\certcli.dll C:\Shared\Autoenroll\
copy %SYSTEMROOT%\system32\certadm.dll C:\Shared\Autoenroll\
(copy %SYSTEMROOT%\system32\certutil.exe C:\Shared\Autoenroll\ This is used by EnrollDomainController and is already available at all DCs.)

Edit or create C:\Shared\Autoenroll\autoenroll.conf

# This is a primitive config file that does not allow spaces
 
# The request URL is built from the following properties
# https://[requestpath]?request=...
#
 
# Standard SSL-port and using URL rewrite from /ejbca/* to /*
requestpath=ca-server.company.local/autoenroll
 
# Non-standard SSL-port and not using URL rewrite
#requestpath=ca-server.company.local:4443/ejbca/autoenroll
 
# Debug setting, use only for manual testing
#debug=true
debug=false

Edit or create C:\Shared\Autoenroll\RequestAndInstall.vbs:

Set oArgs = WScript.Arguments
if oArgs.Count < 1 then
WScript.Echo "Usage: thisscript.vbs fullpathnameofrequest.inf"
WScript.Quit 1
else
sRequestInfo = Trim(oArgs(0))
end if
Set WS = CreateObject("WScript.Shell")
sRequest = WS.ExpandEnvironmentStrings("%TEMP%") & "\autoenrolled.req"
sResult = WS.ExpandEnvironmentStrings("%TEMP%") & "\autoenrolled.p7b"
Set oFilesystem = CreateObject("Scripting.FileSystemObject")
On Error Resume Next ' Ignore if we try to delete a file that does not exist
oFilesystem.DeleteFile(sRequest)
Err.Clear
On Error GoTo 0
sSharedDir = oFilesystem.GetParentFolderName(WScript.ScriptFullName) & "\"
Set iFile = oFilesystem.OpenTextFile(sSharedDir & "autoenroll.conf")
Do While iFile.AtEndOfStream <> True
sLine = iFile.Readline
If InStr(Left(sLine,1), "#") = 0 then
If InStr(sLine, "requestpath=") <> 0 then
sRequestPath = Trim(Right(sLine, Len(sLine)-Len("requestpath=")))
end if
If InStr(sLine, "debug=") <> 0 then
sDebug = Trim(Right(sLine, Len(sLine)-Len("debug=")))
end if
End if
Loop
iFile.Close
WS.Run sSharedDir & "certreq.exe -f -new " & sRequestInfo & " " & sRequest, 0, True
sRequestData = ""
Set objFile = oFilesystem.OpenTextFile(sRequest, 1)
Do Until objFile.AtEndOfStream
sRequestData = sRequestData & objFile.ReadLine
Loop
objFile.Close
set oIE = CreateObject("InternetExplorer.Application")
oIE.navigate2("https://" & sRequestPath & "?debug=" & sDebug & "&request=" & sRequestData)
If sDebug = "true" Then
oIE.visible = true
End If
'Wait max 30 seconds
wscript.sleep 1000
counter = 0
While oIE.Busy = true And counter < 30
counter = counter + 1
wscript.sleep 1000
Wend
sResultData = oIE.Document.Body.innerHTML
sResultData = Mid(sResultData, 6, Len(sResultData)-11)
Set oFile = oFilesystem.CreateTextFile(sResult, True)
oFile.WriteLine sResultData
oFile.Close
on error resume next ' in case the Task Manager is used to close IE.
If sDebug <> "true" Then
oIE.quit ' Close the window
WS.Run sSharedDir & "certreq.exe -accept " & Chr(34) & sResult & Chr(34), 0, True
End If

Edit or create C:\Shared\Autoenroll\EnrollDomainController.vbs:

This Script is based on the script found at http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/advcert.mspx#EURAE
iRole = GetLastDomainRole()
If iRole <> 4 And iRole <> 5 Then
WScript.Echo "This script should only run on a Domain Controller."
WScript.Quit 1
End If
Set WS = CreateObject("WScript.Shell")
Set objDC = GetObject("LDAP://" & CreateObject("ADSystemInfo").ComputerName)
sGUID = objDC.GUID
sDNShostname = objDC.DNShostname
Set oFilesystem = CreateObject("Scripting.FileSystemObject")
sTempfilePrefix = WS.ExpandEnvironmentStrings("%TEMP%") & "\autoenrolled"
sRequestInfo = sTempFilePrefix & ".inf"
sSharedDir = oFilesystem.GetParentFolderName(WScript.ScriptFullName) & "\"
'Create b64 encoded extension
Dim aASNsubstring(2, 5)
Const HEX_DATA_LENGTH = 1
Const ASCIIDATA = 2
Const HEXDATA = 3
Const HEX_BLOB_LENGTH = 4
Const HEX_TYPE = 5
' Encode DNS
aASNsubstring(0, ASCIIDATA) = sDNShostname
aASNsubstring(0, HEX_TYPE) = "82"
For i = 1 to Len(aASNsubstring(0, ASCIIDATA))
aASNsubstring(0, HEXDATA) = aASNsubstring(0, HEXDATA) & Hex(Asc(Mid(aASNsubstring(0, ASCIIDATA), i, 1)))
Next
aASNsubstring(0, HEX_DATA_LENGTH) = ComputeASN1 (Len(aASNsubstring(0, HEXDATA)) / 2)
sASN = aASNsubstring(0, HEX_TYPE) & aASNsubstring(0, HEX_DATA_LENGTH) & aASNsubstring(0, HEXDATA)
' Encode GUID
aASNsubstring(1, HEXDATA) = sGUID
aASNsubstring(1, HEX_TYPE) = "A0"
aASNsubstring(1, HEX_DATA_LENGTH) = ComputeASN1 (Len(aASNsubstring(1, HEXDATA)) / 2)
sASN = sASN & "A01F06092B0601040182371901" & aASNsubstring(1, HEX_TYPE) & "120410" & aASNsubstring(1, HEXDATA)
Set oFile = oFilesystem.CreateTextFile(sTempfilePrefix & ".asn")
oFile.WriteLine "30" & ComputeASN1 (Len(sASN) / 2) & sASN
oFile.Close
WS.Run "certutil -f -decodehex " & sTempfilePrefix & ".asn " & sTempfilePrefix & ".bin", 0, True
WS.Run "certutil -f -encode " & sTempfilePrefix & ".bin " & sTempfilePrefix & ".b64", 0, True
Set iFile = oFilesystem.OpenTextFile(sTempfilePrefix & ".b64")
Set oFile = oFilesystem.CreateTextFile(sRequestInfo, True)
oFile.WriteLine "[Version]"
oFile.WriteLine "Signature= " & Chr(34) & "$Windows NT$" & Chr(34)
oFile.WriteLine ""
oFile.WriteLine "[NewRequest]"
oFile.WriteLine "Subject = " & Chr(34) & "CN=IgnoredValue" & Chr(34)
oFile.WriteLine "KeySpec = 1"
oFile.WriteLine "KeyLength = 2048"
oFile.WriteLine "Exportable = TRUE"
oFile.WriteLine "MachineKeySet = TRUE"
oFile.WriteLine "SMIME = FALSE"
oFile.WriteLine "PrivateKeyArchive = FALSE"
oFile.WriteLine "UserProtected = FALSE"
oFile.WriteLine "UseExistingKeySet = FALSE"
oFile.WriteLine "ProviderName = " & Chr(34) & "Microsoft RSA SChannel Cryptographic Provider" & Chr(34)
oFile.WriteLine "ProviderType = 12"
oFile.WriteLine "RequestType = PKCS10"
oFile.WriteLine "KeyUsage = 0xa0"
oFile.WriteLine ""
oFile.WriteLine "[EnhancedKeyUsageExtension]"
oFile.WriteLine "OID=1.3.6.1.5.5.7.3.1"
oFile.WriteLine "OID=1.3.6.1.5.5.7.3.2"
oFile.WriteLine ""
oFile.WriteLine "[Extensions]"
iLine = 0
Do While iFile.AtEndOfStream <> True
sLine = iFile.Readline
If sLine = "-----END CERTIFICATE-----" then
Exit Do
end if
if sLine <> "-----BEGIN CERTIFICATE-----" then
if iLine = 0 then
oFile.WriteLine "2.5.29.17=" & sLine
else
oFile.WriteLine "_continue_=" & sLine
end if
iLine = iLine + 1
end if
Loop
oFile.WriteLine "Critical=2.5.29.17"
oFile.WriteLine ""
oFile.WriteLine "[RequestAttributes]"
oFile.WriteLine "CertificateTemplate = DomainController"
oFile.Close
iFile.Close
WS.Run sSharedDir & "RequestAndInstall.vbs " & sRequestInfo, 0, True
' Sub
Function ComputeASN1 (iStrLen)
If Len(Hex(iStrLen)) Mod 2 = 0 then
sLength = Hex(iStrLen)
else
sLength = "0" & Hex(iStrLen)
end if
if iStrLen > 127 then
ComputeASN1 = Hex (128 + (Len(sLength) / 2)) & sLength
else
ComputeASN1 = sLength
End If
End Function
'Return the domain role number where:
'-1 Error
'0 Standalone Workstation
'1 Member Workstation
'2 Standalone Server
'3 Member Server
'4 Backup Domain Controller
'5 Primary Domain Controller
Function GetLastDomainRole ()
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select DomainRole from Win32_ComputerSystem",,48)
For Each objItem in colItems
iReturn = objItem.DomainRole
Next
On Error Goto 0
GetLastDomainRole = iReturn
End Function

Edit or create C:\Shared\Autoenroll\EnrollMachine.vbs:

Set WS = CreateObject("WScript.Shell")
Set oFilesystem = CreateObject("Scripting.FileSystemObject")
sRequestInfo = WS.ExpandEnvironmentStrings("%TEMP%") & "\autoenrolled.inf"
Set oFile = oFilesystem.CreateTextFile(sRequestInfo, True)
oFile.WriteLine "[Version]"
oFile.WriteLine "Signature= " & Chr(34) & "$Windows NT$" & Chr(34)
oFile.WriteLine ""
oFile.WriteLine "[NewRequest]"
oFile.WriteLine "Subject = " & Chr(34) & "CN=IgnoredValue" & Chr(34)
oFile.WriteLine "KeyLength = 2048"
oFile.WriteLine "MachineKeySet = TRUE"
oFile.WriteLine "RequestType = PKCS10"
oFile.WriteLine ""
oFile.WriteLine "[RequestAttributes]"
oFile.WriteLine "CertificateTemplate = Machine"
oFile.Close
sSharedDir = oFilesystem.GetParentFolderName(WScript.ScriptFullName) & "\"
WS.Run sSharedDir & "RequestAndInstall.vbs " & sRequestInfo, 0, True

Edit or create C:\Shared\Autoenroll\EnrollUser.vbs:

Set WS = CreateObject("WScript.Shell")
Set oFilesystem = CreateObject("Scripting.FileSystemObject")
sRequestInfo = WS.ExpandEnvironmentStrings("%TEMP%") & "\autoenrolled.inf"
Set oFile = oFilesystem.CreateTextFile(sRequestInfo, True)
oFile.WriteLine "[Version]"
oFile.WriteLine "Signature= " & Chr(34) & "$Windows NT$" & Chr(34)
oFile.WriteLine ""
oFile.WriteLine "[NewRequest]"
oFile.WriteLine "Subject = " & Chr(34) & "CN=IgnoredValue" & Chr(34)
oFile.WriteLine "KeyLength = 2048"
oFile.WriteLine "RequestType = PKCS10"
oFile.WriteLine ""
oFile.WriteLine "[RequestAttributes]"
oFile.WriteLine "CertificateTemplate = User"
oFile.Close
sSharedDir = oFilesystem.GetParentFolderName(WScript.ScriptFullName) & "\"
WS.Run sSharedDir & "RequestAndInstall.vbs " & sRequestInfo, 0, True

Verify that all the file in Shared\Autoenroll directory has read end exec right for Everyone.

Install Certificate Templates by adding the corresponding Snap-in i the MMC console.

  • Install the root CA-certificate(s) in the NTAuthStore, so windows can verify all cerificates produced by EJBCA. Start Menu -> Administration -> Users and Computer -> Right click the domain name -> Properties -> Group Policy -> Edit Default Domain Policy -> Computer Configuration -> Windows Settings -> Security Settings -> Public Key Policies -> Trusted Root Certificate Authorities -> Import -> import the root ca certificate and run "gpupdate /force" on machines that are used for testing. (You can fetch the CA certificate using the EJCBA CLI with "$EJBCA_HOME/bin/ejbca.sh ca getcacert ManagementCA ~/ManagementCA.crt -der".)

  • Add Startup Scripts in Start Menu -> Administration -> Users and Computer -> Right click the domain name -> Properties -> Group Policy -> Edit Default Domain Policy -> Computer Configuration -> Windows Settings -> Scripts -> Startup -> Add the machine-related scripts from the shared directory.

  • Add Login Scripts in Start Menu -> Administration -> Users and Computer -> Right click the domain name -> Properties -> Group Policy -> Edit Default Domain Policy -> User Configuration -> Windows Settings -> Scripts -> Logon -> Add the user-related scripts from the shared directory.

  • Add the ca-server and shared directory to the Intranet Start Menu -> Administration -> Users and Computer -> Right click the domain name -> Properties -> Group Policy -> Edit Default Domain Policy -> Computer Configuration | User Configuration (do both!!) -> Administrative Templates -> Windows Components -> Internet Explorer -> Internet Control Page -> Security Page -> Site to Zone assignement list -> Enabled and added "https://ca-server.company.local" to zone "1", "\\Dc1\Shared" to zone "1"

  • Configure clients to synchronize time using NTP: Start Menu -> Administration -> Users and Computer -> Right click the domain name -> Properties -> Group Policy -> Edit Default Domain Policy -> Computer Configuration -> Administrative Templates -> System -> Windows Time Service -> Time Providers -> Configure Windows NTP Client (Add "dc1.company.local" as an NTP server.) and Enable Windows NTP Client.

  • Use "gpupdate /force" on clients before running tests.

Debugging

You can enable debug by setting *debug=true* in autoenroll.conf to see the response from the Servlet. Test the machine-cert-retreival script by starting a Console as "LocalSystem". C:\Shared\Autoenroll\ConsoleAsLocalSystem.vbs:

Set WS = CreateObject("WScript.Shell")
WS.Run "sc.exe delete lsc", 0, True
WS.Run "sc.exe create lsc binpath= " & Chr(34) & "cmd /K start" & Chr(34) & " type= own type= interact", 0, True
WS.Run "sc.exe start lsc", 0, True

Test the machine-cert-retreival script by starting a Console as "LocalSystem". C:\Shared\ConsoleAsLocalSystem.vbs:

Set WS = CreateObject("WScript.Shell")
WS.Run "sc.exe delete lsc", 0, True
WS.Run "sc.exe create lsc binpath= " & Chr(34) & "cmd /K start" & Chr(34) & " type= own type= interact", 0, True
WS.Run "sc.exe start lsc", 0, True

Adding a custom Administrative template can be done as in this example if needed: Start Menu -> Administration -> Users and Computer -> Right click the domain name -> Properties -> Group Policy -> Edit Default Domain Policy -> Computer Configuration -> Administrative Templates -> Add/Remove Templates -> Add Autoenroll.adm

This is just a sample, but shows how a custom GP can be configured.. (Use the intructions above instead of this template. The example Administrative Template "Autoenroll Related" can be used to force ca-server.company.local into the Intranet zone or add a NTP syncronizing policy. C:\Shared\Autoenroll\Autoenroll.adm:

CLASS MACHINE
 
CATEGORY "Autoenroll Related"
CATEGORY "NTP Synch for clients with AD"
POLICY "Enable NTP synch"
SUPPORTED "This is a hack to get WinXP clients working"
EXPLAIN ".."
KEYNAME "Software\Policies\Microsoft\W32Time\TimeProviders"
VALUENAME "NtpServer"
VALUEON NUMERIC 1
VALUEOFF NUMERIC 0
 
ACTIONLISTON
KEYNAME "Software\Policies\Microsoft\W32Time\Parameters"
VALUENAME "Type"
VALUE "NTP"
KEYNAME "Software\Policies\Microsoft\W32Time\Config"
VALUENAME "AnnounceFlags"
VALUE NUMERIC 5
KEYNAME "Software\Policies\Microsoft\W32Time\Config"
VALUENAME "MaxPosPhaseCorrection"
VALUE NUMERIC 1099511627775
KEYNAME "Software\Policies\Microsoft\W32Time\Config"
VALUENAME "MaxNegPhaseCorrection"
VALUE NUMERIC 1099511627775
END ACTIONLISTON
 
PART "NTP Servers in the form ntp.server1.com,0x1 ntp.server2.com,0x1 ntp.server3.com,0x1" EDITTEXT
KEYNAME "Software\Policies\Microsoft\W32Time\Parameters"
VALUENAME "NtpServer"
MAXLEN 4096
END PART
 
PART "Poll interval in seconds" NUMERIC
KEYNAME "Software\Policies\Microsoft\W32Time\TimeProviders\NtpClient"
VALUENAME "SpecialPollInterval"
DEFAULT 900
END PART
END POLICY
END CATEGORY
 
CATEGORY "Required trust"
POLICY "Trust ca-server.company.local"
SUPPORTED "Might need IE6 for this to work.."
EXPLAIN "This adds the ca-server.company.local to the list of intranet-sites.."
KEYNAME "Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\company.local\ca-server"
VALUENAME "https"
VALUEON NUMERIC 1
VALUEOFF NUMERIC 0
END POLICY
END CATEGORY
END CATEGORY
 
CLASS USER
 
CATEGORY "Autoenroll Related"
CATEGORY "Required trust"
POLICY "Trust ca-server.company.local"
SUPPORTED "Might need IE6 for this to work.."
EXPLAIN "This adds the ca-server.company.local to the list of intranet-sites.."
KEYNAME "Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\company.local\ca-server"
VALUENAME "https"
VALUEON NUMERIC 1
VALUEOFF NUMERIC 0
END POLICY
END CATEGORY
END CATEGORY

Useful reg-for VMwares with runaway clocks if GP mod didn't work or you want to modify a single client:

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config]
"AnnounceFlags"=dword:00000005
"MaxPosPhaseCorrection"=dword:ffffffff
"MaxNegPhaseCorrection"=dword:ffffffff
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Parameters]
"Type"="NTP"
"NtpServer"="dc1.company.local,0x1"
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Parameters\NtpServer]
"NtpServer"="dc1.company.local,0x1"
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient]
"SpecialPollInterval"=dword:00000030
 
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer]
"Enabled"=dword:00000001

References

Other auto enroll references: