Continuing the story about new release I will talk about two interesting features.
Windows CA supports extension addition to a certificate request. Sometimes it is necessary. For example, IIS admin submitted certificate request for one of the web site. He used IIS Manager console to generate request. The biggest drawback of the IIS certificate request manager – it doesn’t allow you to specify subject alternative names (SAN). Or another example, some application requires custom extension which cannot be added through Certificate Templates console. Or, maybe, certificate request contains some unwanted extensions and you want to disable them. Set-CertificateExtension command will be very handy in such situations.
Why not to modify certificate request directly? Sure, you can, but you will break signature and no CA will accept it. And direct certificate edit isn’t that simple task, so don’t think about this.
Microsoft CA supports extension value modification (as well, as addition and removal) in a timeframe between certificate request is submitted and processed by a policy module. Normally, Windows CA immediately passes incoming requests to policy module. With the only exception, when certificate request is pending for CA manager approval.
There is ‘certutil –setextension’ command that does the same, however it’s syntax is too cryptic even for me. My own implementation isn’t very simple for use, but more convenient for users who ever worked with .NET X509 extensions.
At first, we need to prepare extension object to add. There are several predefined in native .NET stored in the X509Certificates namespace (look for classes that ends with “Extension” suffix). In addition, I wrote several extension classes in the same namespace: X509Certificates.
If you are creating an X509 extension class, it must inherit from X509Extension base class.
They behave exactly as .NET native with the only exception – these extensions do not rely on unmanaged functions, all encoders and decoders are managed. Let’s add something simple, for example, Basic Constraints extension:
$bc = New-Object security.cryptography.x509certificates.x509basicconstraintsextension 0,0,0,0 Get-CA dc2* | Get-PendingRequest -RequestID 1622 | Set-CertificateExtension -Extension $bc
PS C:\> $bc = New-Object security.cryptography.x509certificates.x509basicconstraintsextension 0,0,0,0 PS C:\> $bc CertificateAuthority : False HasPathLengthConstraint : False PathLengthConstraint : 0 Critical : False Oid : 2.5.29.19 (Basic Constraints) RawData : {48, 0} PS C:\> Get-CA dc2* | Get-PendingRequest -RequestID 1622 | Set-CertificateExtension -Extension $bc -Verbose VERBOSE: Extension 'Basic Constraints' was addedd to request ID='1622'. RequestID : 1622 Request.RequesterName : CONTOSO\DC2$ Request.SubmittedWhen : 2013.11.18. 15:55:50 Request.CommonName : CertificateTemplate : Web Server V2 RowId : 1622 ConfigString : dc2.contoso.com\contoso-DC2-CA Table : Request PS C:\>
Now, if we issue the certificate it will contain Basic Constraints extension issued to End Entity without path length constraint and is not marked critical. Plain and simple. Doesn’t? Moreover, the code returns request row object, so it can be piped to Approve-CertificateRequest to issue the certificate.
In order to remove specific extension, pass extension OID to the Extension parameter and enable Remove switch:
PS C:\> Get-CA dc2* | Get-PendingRequest -RequestID 1622 | Set-CertificateExtension -Extension 2.5.29.19 -Remove -Verbose
VERBOSE: Extension OID='2.5.29.19' was removed from request ID='1622'.
RequestID : 1622
Request.RequesterName : CONTOSO\DC2$
Request.SubmittedWhen : 2013.11.18. 15:55:50
Request.CommonName :
CertificateTemplate : Web Server V2
RowId : 1622
ConfigString : dc2.contoso.com\contoso-DC2-CA
Table : Request
PS C:\>
This is another handy functionality. There are 4 commands that are used to manage CA security (ACL):
These commands are self-explanatory. I tried various designs and ended up with a regular .NET-style ACL object. You can even use Get-ACL on Certification Authority object:
PS C:\> Get-CA dc2* | Get-CAACL Path Owner Access ---- ----- ------ BUILTIN\Administrators NT AUTHORITY\Authenticated Users All... PS C:\> (Get-CA dc2* | Get-CAACL).access CertificationAuthorityRights : Read, Enroll AccessControlType : Allow IdentityReference : NT AUTHORITY\Authenticated Users IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\Domain Admins IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\Enterprise Admins IsInherited : False InheritanceFlags : None PropagationFlags : None PS C:\>
Looks very familiar. CA ACL is simpler than, say, file system ACL, because it doesn’t use ACL inheritance and ACL propagation and uses very simple permissions:
PS C:\> [enum]::GetNames([PKI.Security.AccessControl.CertificationAuthorityRights]) ManageCA ManageCertificates Read Enroll PS C:\>
Exactly four entries, like in Certification Authority MMC:
Permission addition consist of access control entry (ACE) object creation:
$account = [Security.Principal.NTAccount]"domain\username" New-Object PKI.Security.AccessControl.CertificationAuthorityAccessRule $account, $AccessMask, $AccessType
Or one-liner:
New-Object PKI.Security.AccessControl.CertificationAuthorityAccessRule ([Security.Principal.NTAccount]"domain\username"), $AccessMask, $AccessType
PS C:\> Get-CA dc2* | Get-CAACL | Add-CAACL -AccessControlEntry (new-object PKI.Security.AccessControl.CertificationAuth orityAccessRule ([security.principal.ntaccount]"acl"), managecertificates, allow) | Set-CASecurityDescriptor -RestartCA PS C:\> (Get-CA dc2* | Get-CAACL).access CertificationAuthorityRights : Read, Enroll AccessControlType : Allow IdentityReference : NT AUTHORITY\Authenticated Users IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\Domain Admins IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\Enterprise Admins IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\acl IsInherited : False InheritanceFlags : None PropagationFlags : None PS C:\>
Very easy task. The only note here is that, there is allowed only one entry per account. Therefore, if particular user account (or group) is already listed in the ACL, new ACE will not be added, instead, you should remove this account from ACL and add new ACE. Account removal is simpler, you need to specify account name to remove:
PS C:\> Get-CA dc2* | Get-CAACL | Remove-CAACL -User "acl" | Set-CAACL -RestartCA PS C:\> (Get-CA dc2* | Get-CAACL).access CertificationAuthorityRights : Read, Enroll AccessControlType : Allow IdentityReference : NT AUTHORITY\Authenticated Users IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : BUILTIN\Administrators IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\Domain Admins IsInherited : False InheritanceFlags : None PropagationFlags : None CertificationAuthorityRights : ManageCA, ManageCertificates AccessControlType : Allow IdentityReference : CONTOSO\Enterprise Admins IsInherited : False InheritanceFlags : None PropagationFlags : None PS C:\>
Very easy. CA ACL management via certutil would be a real nightmare. This is another place where PowerShell takes over certutil.
In the next post I will talk about dealing with X509 certificate requests in PowerShell.
Hi
Thank you for your useful information. Could you please explain how can I add a certificate policy with an OID and a URL address to a request by use of this method? I really need your help.
Post your comment:
Comments: