dsccommunity / CertificateDsc

DSC resources to simplify administration of certificates on a Windows Server.
https://dsccommunity.org
MIT License
122 stars 69 forks source link

[New Resource] xServerCertReq #54

Open alexjebens opened 7 years ago

alexjebens commented 7 years ago

I have a custom Document Signing Certificate Template that I would like to request from the CA.

There are 2 reasons the current implementation of xCertReq does not work for this:

  1. The issued Certificate does not have a Subject even if you put one in the inf. Therefore the Primary Key would have to be the friendly name.
  2. It fails if you use "[RequestAttributes]CertificateTemplate = $CertificateTemplate" in the inf. You need to remove that line and instead use certreq -submit -q -attrib CertificateTemplate:$CertificateTemplate -config $CA $ReqPath $CerPath

I would be happy to implement this if the CR is accepted.

alexjebens commented 7 years ago

Other appropriate names for the Resource might be xComputerCertReq or xDocumentSigningCertReq

For Reference:

The Custom Certificate Template that I am using is enabled for all Domain Coumputers. It is based on the Workstation Template. The properties are: "pKIDefaultKeySpec" = "1" "pKIKeyUsage" = "0x30" "pKIMaxIssuingDepth" = "0" "pKICriticalExtensions" = "2.5.29.15" "pKIExpirationPeriod" = "0 64 57 135 46 225 254 255" "pKIOverlapPeriod" = "0 128 166 10 255 222 255 255" "pKIExtendedKeyUsage" = "1.3.6.1.5.5.7.3.2" "pKIDefaultCSPs" = "1,Microsoft RSA SChannel Cryptographic Provider" "msPKI-RA-Signature" = "0" "msPKI-Enrollment-Flag" = "32" "msPKI-Private-Key-Flag" = "0" "msPKI-Certificate-Name-Flag" = "134217728" "msPKI-Minimal-Key-Size" = "2048" "msPKI-Template-Schema-Version" = "2" "msPKI-Template-Minor-Revision" = "0" "msPKI-Cert-Template-OID" = "1.3.6.1.4.1.311.21.8.16146803.10615762.2181305.874203.5733703.45.5340052.3640521" "msPKI-Certificate-Application-Policy" = "1.3.6.1.4.1.311.80.1"

PlagueHO commented 7 years ago

Hi @aboersch - thanks for submitting this issue - and the offer to resolve it! :grin:

I'm wondering if there is something else there is going on here? Are you able to post the output of the DSC logs for this and also the DSC Config you're using?

I added a Document Signing certificate template (that hopefully should have been the same as yours) to my CA and was able to issue a cert from it using the same basic code from the resource.

Could you check that the CertificateTemplate name you're passing to the resource does not contain spaces (e.g. "DocumentSigning" - not "Document Signing")?

alexjebens commented 7 years ago

Allow me to first explain what I am trying achieve: I have created a Document Signing Template using PowerShell on my CA. The purpose of the issued Certificates will be encrypting Credentials in MOFs for DSC as per Microsoft specs. Now I am trying to get the DSC clients to request such a Certificate.

The name of the Certificate Template is "DSC", no spaces or anything else.

Here is the code to create the template:

$templateName = "DSC"
$configContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext 
$ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$configContext" 
$template = [ADSI]"LDAP://CN=$templateName,CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"

if([string]::IsNullOrEmpty($template.Name)){
    # create if not exists
    $template = $ADSI.Create("pKICertificateTemplate", "CN=$($templateName)")
}

$template.Put("displayName", $templateName)
$template.SetInfo()

$pkiConfig = @{
    "pKIDefaultKeySpec" = "1"
    "pKIKeyUsage" = "160 0"
    "pKIMaxIssuingDepth" = "0"
    "pKICriticalExtensions" = "2.5.29.15"
    "pKIExpirationPeriod" = "0 64 57 135 46 225 254 255"
    "pKIOverlapPeriod" = "0 128 166 10 255 222 255 255"
    "pKIExtendedKeyUsage" = "1.3.6.1.5.5.7.3.2"
    "pKIDefaultCSPs" = "1,Microsoft RSA SChannel Cryptographic Provider"
    "msPKI-RA-Signature" = "0"
    "msPKI-Enrollment-Flag" = "32"
    "msPKI-Private-Key-Flag" = "0"
    "msPKI-Certificate-Name-Flag" = "134217728"
    "msPKI-Minimal-Key-Size" = "2048"
    "msPKI-Template-Schema-Version" = "2"
    "msPKI-Template-Minor-Revision" = "0"
    "msPKI-Cert-Template-OID" = "1.3.6.1.4.1.311.21.8.16146803.10615762.2181305.874203.5733703.45.5340052.3640521"
    "msPKI-Certificate-Application-Policy" = "1.3.6.1.4.1.311.80.1"
}
foreach($key in $pkiConfig.Keys){
    $template.Put($key, $pkiConfig[$key])
}

# Does not work correctly if not done like this
$k = new-Object Byte[] 1
$k[0] = 48 # = 0x30
$template.InvokeSet("pKIKeyUsage", $k)
$template.SetInfo()

# Allow Computers to Enroll
$template.ObjectSecurity.GetAccessRules($true, $true, [System.Security.Principal.NTAccount])
$acc = [System.Security.Principal.NTAccount]::new($Using:domainNetbiosName, "Domain Computers")
$enrollObjectType = [Guid]::Parse("0e10c968-78fb-11d2-90d4-00c04f79dc55")
$adRights = [System.DirectoryServices.ActiveDirectoryRights]::ReadProperty -bor [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty -bor [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight
$rule = [System.DirectoryServices.ActiveDirectoryAccessRule]::new($acc, $adRights, [System.Security.AccessControl.AccessControlType]::Allow, $enrollObjectType)
$template.ObjectSecurity.AddAccessRule($rule)
$template.commitchanges()

Should you have a better Template for DSC signing please be so kind as to share your properties here. You can read them using:

$templateName = "Workstation"

$ConfigContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext 
$ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"
$template = [ADSI]"LDAP://CN=$templateName,CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext"
$template.Properties.PropertyNames | ? {$_.StartsWith("pKI") -or $_.StartsWith("msPKI-")} | % {
    Write-Host """$_"" = ""$($template.psbase.Properties.Item($_).ToString())"""
}

I am currently unable to get the exact error message and will add later but the REQ File was not being created when I included the following in the INF:

@"
[RequestAttributes]
CertificateTemplate = $CertificateTemplate
"@
alexjebens commented 7 years ago

Here is the error from DSC:

PowerShell DSC resource MSFT_xCertReq  failed to execute Set-TargetResource functionality with error message: Certificate Request file 'C:\Windows\TEMP\xCertReq-b48146a6-ad71-4cc2-8cf9-4f7030adf411.req' not 
found.

If I invoke the certreq manually: & certreq.exe @('-submit','-q','-config',"$CAName","C:\Windows\Temp\xCertReq-015bb903-c3bd-4707-91e6-38c74caa70e8.inf","C:\Windows\Temp\xCertReq-015bb903-c3bd-4707-91e6-38c74caa70e8.cer") I get: Certificate Request Processor: ASN1 bad tag value met. 0x8009310b (ASN: 267 CRYPT_E_ASN1_BADTAG)

This is the config I used

configuration Test{
    Import-DscResource -ModuleName xCertificate
    node localhost {
        LocalConfigurationManager{
            RefreshMode = 'Push'
        }
        xCertReq cert {
            Subject = $env:COMPUTERNAME
            CAServerFQDN = #<Redacted>
            KeyLength = 2048
            CARootName = #<Redacted>
            ProviderName = 'Microsoft RSA SChannel Cryptographic Provider'
            OID = '1.3.6.1.4.1.311.80.1'
            CertificateTemplate = 'DSC'
        }
    }
}

Test

Set-DscLocalConfigurationManager -Path .\TEST
Start-DscConfiguration -Wait -Verbose -Path .\TEST

And here is the generated INF:

[NewRequest] Subject = "CN=#redacted#" KeySpec = 1 KeyLength = 2048 Exportable = TRUE MachineKeySet = TRUE SMIME = FALSE PrivateKeyArchive = FALSE UserProtected = FALSE UseExistingKeySet = FALSE ProviderName = Microsoft RSA SChannel Cryptographic Provider ProviderType = 12 RequestType = CMC KeyUsage = 0xa0 [RequestAttributes] CertificateTemplate = DSC [EnhancedKeyUsageExtension] OID = 1.3.6.1.4.1.311.80.1

PlagueHO commented 7 years ago

Hi @aboersch - That is some great info. I'm just doing some work on this resource and will give this a try and include your suggested changes to see if it causes any other side affects (e.g. passes all regression tests)

PlagueHO commented 7 years ago

Hi @aboersch - I've figured out what the issue is: The xCertReq resource can only request certificates for a machine - it can't request user certificates because the DSC LCM always runs under a machine context (even if you're logged onto the node and applying the config manually).

The DSC template above DSC is created as a user certificate, so xCertReq can't issue it - but you could issue it yourself if you're logged on because you're issuing it under a user context.

So what you'd need to do is create a template that is based on a machine certificate. In my case I just duplicated the Computer template and customized it as per this page.

This is the output of the cert I created:

"pKIDefaultKeySpec" = "1"
"pKIKeyUsage" = "176"
"pKIMaxIssuingDepth" = "0"
"pKICriticalExtensions" = "2.5.29.15"
"pKIExpirationPeriod" = "0 64 57 135 46 225 254 255"
"pKIOverlapPeriod" = "0 128 166 10 255 222 255 255"
"pKIExtendedKeyUsage" = "1.3.6.1.4.1.311.80.1"
"pKIDefaultCSPs" = "1,Microsoft RSA SChannel Cryptographic Provider"
"msPKI-RA-Signature" = "0"
"msPKI-Enrollment-Flag" = "32"
"msPKI-Private-Key-Flag" = "16842752"
"msPKI-Certificate-Name-Flag" = "134217728"
"msPKI-Minimal-Key-Size" = "2048"
"msPKI-Template-Schema-Version" = "2"
"msPKI-Template-Minor-Revision" = "7"
"msPKI-Cert-Template-OID" = "1.3.6.1.4.1.311.21.8.7559389.32918.1590937.4996186.12020124.235.10768362.8251361"
"msPKI-Certificate-Application-Policy" = "1.3.6.1.4.1.311.80.1"

Does that make sense and/or help?

alexjebens commented 7 years ago

Hi, the above Certificate Template is based on a computer certificate. I am able to request it as the system account, though that issue does affect the the repro i reported

PlagueHO commented 7 years ago

Hi @aboersch - hmm that is odd.

The error is actually occurring when converting the .INF into a .REQ. When you're doing this manually you're directly submitting the *.INF:

& certreq.exe @('-submit','-q','-config',"$CAName","C:\Windows\Temp\xCertReq-015bb903-c3bd-4707-91e6-38c74caa70e8.inf","C:\Windows\Temp\xCertReq-015bb903-c3bd-4707-91e6-38c74caa70e8.cer")

Can you try:

& certreq.exe @('-new','-q','-config',"$CAName","C:\Windows\Temp\xCertReq-015bb903-c3bd-4707-91e6-38c74caa70e8.inf","C:\Windows\Temp\xCertReq-015bb903-c3bd-4707-91e6-38c74caa70e8.req")

Does this create the *.REQ file?