Skip to content

[Feature request] Implement way to manage certificate managers/enrolment agents rights #12

@jalliot

Description

@jalliot

See blog post https://www.sysadmins.lv/blog-en/how-to-read-adcs-enrollment-agentcertificate-manager-rights-in-powershell.aspx

This would be good to have this officially implemented in pkix.net/PSPKI module and thus be able to read but also write certificate managers and enrolment agents rights.

One step further would be to implement a method actually checking the current user's permissions (based on its current security token) for a given template.
I did write such a method some time ago, using a slightly modified version of your Get-OfficerRights function from the blog post. It is quite ugly but if it may help you some bit, here it is:

# We don't use the simpler $CertificationAuthority.GetMyRoles() either because it
# does not check "deny only" SIDs and does not test certificate mnagers restrictions
function Test-CertificateManager {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('CA')]
        [PKI.CertificateServices.CertificateAuthority] $CertificationAuthority,

        [PKI.CertificateTemplates.CertificateTemplate] $Template
    )

    # Get current user's identities
    $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $allowedSids = @($currentUser.UserClaims |
        Where-Object Type -in ([System.Security.Claims.ClaimTypes]::PrimaryGroupSid,
                               [System.Security.Claims.ClaimTypes]::PrimarySid,
                               [System.Security.Claims.ClaimTypes]::GroupSid,
                               [System.Security.Claims.ClaimTypes]::Sid) |
        ForEach-Object { $_.Value })
    $deniedSids = $allowedSids + @($currentUser.UserClaims |
        Where-Object Type -in ([System.Security.Claims.ClaimTypes]::DenyOnlyPrimaryGroupSid,
                               [System.Security.Claims.ClaimTypes]::DenyOnlyPrimarySid,
                               [System.Security.Claims.ClaimTypes]::DenyOnlySid) |
        ForEach-Object { $_.Value })

    $denied = $false
    $allowed = $false
    (Get-CASecurityDescriptor -CertificationAuthority $CertificationAuthority).Access |
        Where-Object {
            $_.CertificationAuthorityRights -band [PKI.Security.AccessControl.CertificationAuthorityRights]::ManageCertificates
        } |
        ForEach-Object {
            $sid = $_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value
            if ($_.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Deny -and $sid -in $deniedSids) {
                $denied = $true
            } elseif ($_.AccessControlType -eq [System.Security.AccessControl.AccessControlType]::Allow -and $sid -in $allowedSids) {
                $allowed = $true
            }
        }

    $isOfficer = -not $denied -and $allowed
    if (-not $Template -or -not $isOfficer) {
        return $isOfficer
    }

    # Test certificate managers restrictions
    $CertAdmin = New-Object -ComObject CertificateAuthority.Admin
    try {
        $aclBytes = $CertAdmin.GetConfigEntry($CertificationAuthority.ConfigString, [String]::Empty, 'OfficerRights')
        $denied = $false
        $allowed = $false
        Convert-OfficerRights $aclBytes |
            Where-Object { [String]::IsNullOrEmpty($_.Template) -or $_.Template.Value -eq $Template.OID.Value } |
            Where-Object {
                $ret = $false
                $toBeTestedSids = if ($_.AceType -eq [System.Security.AccessControl.AceQualifier]::AccessDenied) { $deniedSids } else { $allowedSids }
                $_.Securables | ForEach-Object { $ret = $ret -or $_ -in $toBeTestedSids }
                $ret
            } |
            ForEach-Object {
                if ($_.AceType -eq [System.Security.AccessControl.AceQualifier]::AccessDenied -and $_.Officer -in $deniedSids) {
                    $denied = $true
                } elseif ($_.AceType -eq [System.Security.AccessControl.AceQualifier]::AccessAllowed -and $_.Officer -in $allowedSids) {
                    $allowed = $true
                }
            }

        return -not $denied -and $allowed

    } catch {
        # There is no restriction applied so return previous result
        return $isOfficer
    } finally {
        [void] [Runtime.InteropServices.Marshal]::ReleaseComObject($CertAdmin)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions