private/functions/Revoke-AxisCertificateOnDogtag.ps1
|
function Revoke-AxisCertificateOnDogtag { <# .SYNOPSIS Revokes a certificate on a Dogtag PKI CA through its agent REST API. .DESCRIPTION EST has no revocation operation, so Dogtag's CA REST API is used: POST <Server>/ca/rest/agent/certs/<serial>/revoke Content-Type: application/json {"Reason":"Superseded"} Serial: Dogtag CertId accepts decimal or "0x"-prefixed hex (CertId.java), so the hex serial is sent as 0x<HEX>. Reason labels are those of org.mozilla.jss.netscape.security.x509.RevocationReason, matched case-insensitively: Unspecified, Key_Compromise, CA_Compromise, Affiliation_Changed, Superseded, Cessation_of_Operation, Certificate_Hold, Remove_from_CRL, Privilege_Withdrawn, AA_Compromise. Unknown labels fall back to Unspecified on the server. Body fields (CertRevokeRequest.java): Reason, InvalidityDate, Comments, Encoded, Nonce (all optional). Sources: https://github.com/dogtagpki/pki/blob/v11.5.0/base/common/src/main/java/com/netscape/certsrv/cert/AgentCertResource.java https://github.com/dogtagpki/pki/blob/master/base/ca/src/main/java/org/dogtagpki/server/ca/rest/v2/AgentCertServlet.java https://github.com/dogtagpki/pki/blob/master/base/common/src/main/java/com/netscape/certsrv/cert/CertRevokeRequest.java https://github.com/dogtagpki/jss/blob/master/base/src/main/java/org/mozilla/jss/netscape/security/x509/RevocationReason.java The caller must be a member of "Certificate Manager Agents". Dogtag agent resources are mapped to the "certs" auth method; in a default install that means client certificate authentication (agent cert) and, depending on /var/lib/pki/<instance>/ca/conf/auth-method.properties, HTTP Basic may or may not be accepted - UNCONFIRMED, see worker_est.md. Both are attempted: a client certificate when ClientCertThumbprint is set, HTTP Basic from RevokeCredentialTarget (falls back to CredentialTarget) otherwise. Authority keys used: Server ('https://host:8443'), RestPath (optional, default '/ca/rest'; use '/ca/v2' for the servlet-based v2 API), ClientCertThumbprint, RevokeCredentialTarget / CredentialTarget, SkipCertificateCheck. .PARAMETER Authority The authority hashtable from $Config.CertificateAuthorities. .PARAMETER Serial Serial number of the certificate to revoke (hex, uppercase, no colons - as returned by the Submit function). .PARAMETER Reason Superseded (default), KeyCompromise, CessationOfOperation or Unspecified. #> [cmdletbinding()] Param( [Parameter(Mandatory)] [Hashtable]$Authority, [Parameter(Mandatory)] [String]$Serial, [Parameter()] [ValidateSet("Superseded","KeyCompromise","CessationOfOperation","Unspecified")] [String]$Reason="Superseded" ) if(!$Authority.Server) { Throw "Authority has no Server (expected 'https://host:8443')" } $CAName = $Authority.Name if(!$CAName) { $CAName = $Authority.Server } $ReasonMap = @{ Superseded = "Superseded" KeyCompromise = "Key_Compromise" CessationOfOperation = "Cessation_of_Operation" Unspecified = "Unspecified" } $HexSerial = ($Serial -replace '[^0-9A-Fa-f]','').ToUpper() if(!$HexSerial) { Throw "Serial '$Serial' is not a hex serial number" } $RestPath = "/ca/rest" if($Authority.RestPath) { $RestPath = "/$($Authority.RestPath.Trim('/'))" } $Uri = "$($Authority.Server.TrimEnd('/'))$RestPath/agent/certs/0x$HexSerial/revoke" $Param = @{ Method = 'POST' Uri = $Uri UseBasicParsing = $true TimeoutSec = 60 ContentType = 'application/json' Headers = @{ Accept = 'application/json' } Body = (ConvertTo-Json -Compress @{ Reason = $ReasonMap[$Reason] }) Verbose = $false ErrorAction = 'Stop' } if($Authority.SkipCertificateCheck) { if($PSVersionTable.PSVersion.Major -ge 6) { $Param.Add('SkipCertificateCheck',$true) } else { Set-CertificateValidation -Disable } } $Authenticated = $false if($Authority.ClientCertThumbprint) { if(!(Test-Path "Cert:\CurrentUser\My")) { Throw "ClientCertThumbprint requires the Windows certificate store (Cert:\CurrentUser\My) which is not available on this platform" } $ClientCert = Get-ChildItem "Cert:\CurrentUser\My" | Where-Object { $_.Thumbprint -eq $Authority.ClientCertThumbprint } | Select-Object -First 1 if(!$ClientCert) { Throw "Client certificate $($Authority.ClientCertThumbprint) not found in Cert:\CurrentUser\My" } $Param.Add('Certificate',$ClientCert) $Authenticated = $true } $CredentialTarget = $Authority.RevokeCredentialTarget if(!$CredentialTarget) { $CredentialTarget = $Authority.CredentialTarget } if(!$CredentialTarget -and $Authority.Name) { $CredentialTarget = "AxisPowershell-CA-$($Authority.Name)" } if($CredentialTarget) { $Credential = Get-StoredCredential -Target $CredentialTarget if($Credential) { $Pair = "$($Credential.UserName):$($Credential.GetNetworkCredential().Password)" $Param.Headers["Authorization"] = "Basic $([Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Pair)))" $Authenticated = $true } } if(!$Authenticated) { Throw "No agent credential for $CAName : set ClientCertThumbprint or store a credential with New-StoredCredential -Target '$CredentialTarget' -Persist Enterprise" } Write-Verbose "POST $Uri ($($ReasonMap[$Reason]))" Try { $Response = Invoke-WebRequest @Param } Catch { $Detail = $_.Exception.Message if($_.ErrorDetails.Message) { $Detail = "$Detail $($_.ErrorDetails.Message)" } Throw "Dogtag revocation of $HexSerial failed on $CAName ($Uri): $Detail" } #Response is a CertRequestInfo JSON document; operationResult/requestStatus names are UNCONFIRMED (see worker_est.md) $Content = $Response.Content if($Content -is [Byte[]]) { $Content = [System.Text.Encoding]::UTF8.GetString($Content) } $Info = $null if($Content) { Try { $Info = $Content | ConvertFrom-Json } Catch { Write-Verbose "Dogtag: non-JSON revocation response ($Content)" } } if($Info.operationResult -and $Info.operationResult -ne "success") { Throw "Dogtag revocation of $HexSerial on $CAName returned operationResult '$($Info.operationResult)': $($Info.errorMessage)" } if($Info.requestStatus) { Write-Verbose "Dogtag revocation request $($Info.requestID): $($Info.requestStatus)" } Write-Log -ID "Certificates" -Message "Revoked $HexSerial on $CAName ($($ReasonMap[$Reason]))" return $true } |