I think, I have to publish several articles that would cover common PKI/ADCS administration tasks with PowerShell by using my PowerShell PKI module (of course!). Today I'll cover very simple, but very common task: managing pending certificate requests.
In this post we would propose the following scenario:
Just to make it clear, CA manager approval is configured in the certificate template, as follows:
you, as CA manager, received notification about incoming certificate request. Your task is to review the certificate request to ensure that it is properly constructed and conforms internal security policies and then make decision: approve or deny certificate request. You can do this by using Certification Authority MMC snap-in, but this would require a lot of clicks and without having a chance to automate this. Another solution that includes PowerShell offers you great automation capabilites.
PSPKI module has Get-PendingRequest command that retrieves pending requests from CA database. So, let's start:
PS C:\> Import-Module PSPKI PS C:\> $ca = Get-CertificationAuthority dc2* PS C:\> Get-PendingRequest -CA $ca RequestID : 1847 Request.RequesterName : CONTOSO\DC2$ Request.SubmittedWhen : 2016.02.05. 9:42:54 Request.CommonName : www.contoso.com CertificateTemplate : Web Server V2 RowId : 1847 ConfigString : dc2.contoso.com\contoso-DC2-CA Table : Request RequestID : 1849 Request.RequesterName : CONTOSO\DC2$ Request.SubmittedWhen : 2016.02.05. 10:16:57 Request.CommonName : www.contoso.com CertificateTemplate : Web Server V2 RowId : 1849 ConfigString : dc2.contoso.com\contoso-DC2-CA Table : Request PS C:\>
We see two incoming requests. Both are generated against "Web Server V2" certificate and for "www.contoso.com" name. Why two? It doesn't really matter. Internal portal could be hosted on NLB cluster and each node would have its own certificate. Doesn't matter, we should review both certificates. Default output of the Get-PendingRequest command returns only few properties about the request. We want to look at request details deeper. We would include "Request.RawRequest" column that contains original PKCS#10/PKCS#7 certificate request:
PS C:\> $row = Get-PendingRequest -CA $ca -Property "RawRequest" -RequestID 1847 PS C:\> $row RequestID : 1847 Request.RequesterName : CONTOSO\DC2$ Request.SubmittedWhen : 2016.02.05. 9:42:54 Request.CommonName : www.contoso.com CertificateTemplate : Web Server V2 Request.RawRequest : MIIFKQYJKoZIhvcNAQcCoIIFGjCCBRYCAQMxCzAJBgUrDgMCGgUAMIIEBgYIKwYB BQUHDAKgggP4BIID9DCCA/AwZDBiAgECBgorBgEEAYI3CgoBMVEwTwIBADADAgEB MUUwQwYJKwYBBAGCNxUUMTYwNAIBBQwPZGMyLmNvbnRvc28uY29tDBVDT05UT1NP XEFkbWluaXN0cmF0b3IMB01NQy5FWEUwggOCoIIDfgIBATCCA3cwggLgAgEAMFUx IDAeBgNVBAoMF0NvbnRvc28gUGhhcm1hY2V1dGljYWxzMRcwFQYDVQQLDA5EaXZp c2lvbiBvZiBJVDEYMBYGA1UEAwwPd3d3LmNvbnRvc28uY29tMIGfMA0GCSqGSIb3 DQEBAQUAA4GNADCBiQKBgQDUNydDNjIqqJyMlVeMoPmEKB7sxsStSgaTn/RrGdhE fzDWh/Xg/HySweUc28FsKbRenBuscAdEYMjdzwQjIPtKJg5V1MVob4MESnFVqML8 slO+NkUjXYUfL3yH4z8ZAg7/nTCuKFE6S+xzbG1i4Ct5FZKGAF+JDB9LaFFWi53X tQIDAQABoIIB4DAaBgorBgEEAYI3DQIDMQwWCjYuMC42MDAyLjIwQwYJKwYBBAGC NxUUMTYwNAIBBQwPZGMyLmNvbnRvc28uY29tDBVDT05UT1NPXEFkbWluaXN0cmF0 b3IMB01NQy5FWEUwcgYKKwYBBAGCNw0CAjFkMGICAQEeWgBNAGkAYwByAG8AcwBv AGYAdAAgAFIAUwBBACAAUwBDAGgAYQBuAG4AZQBsACAAQwByAHkAcAB0AG8AZwBy AGEAcABoAGkAYwAgAFAAcgBvAHYAaQBkAGUAcgMBADCCAQcGCSqGSIb3DQEJDjGB +TCB9jA8BgkrBgEEAYI3FQcELzAtBiUrBgEEAYI3FQiJkAaDvrg7h8GPD4S48iqB 4e9VJYaFzFmGxegkAgFkAgEHMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQE AwIFoDBYBgNVHSAEUTBPME0GJSsGAQQBgjcVCImQBoO+uDuHwY8PhLjyKoHh71Ul hrnBAIL59TMwJDAiBggrBgEFBQcCARYWaHR0cDovL3d3dy5jb250b3NvLmNvbTAb BgkrBgEEAYI3FQoEDjAMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBRfhF+Ikq/9hiD4 U3Oj5MfoFSKybDANBgkqhkiG9w0BAQUFAAOBgQDPUKo5kRhWLmxHkRGt6GG5Kt6M +B/8DFQjq5l3IUc8Of2llgLXbzsafTByo22mm1Zr+jZ5XuOFMBMjModIgzgPL599 bO1SgHEtZdC6UIxECMNe+Pr1Sy7kr4lxM+A6T1rDDdd0JIn3e2fIPDQWlZT0r3ap FdoYDQ/SBOjaFTgJhjAAMAAxgfkwgfYCAQOAFF+EX4iSr/2GIPhTc6Pkx+gVIrJs MAkGBSsOAwIaBQCgPjAXBgkqhkiG9w0BCQMxCgYIKwYBBQUHDAIwIwYJKoZIhvcN AQkEMRYEFLzmQsISbCiv4csQ/TnMRsVcgHVcMA0GCSqGSIb3DQEBAQUABIGAZ9KT YiPVFu2wM88yjPPlx3AsnpK0IbULx75qEEN4nHz+5raRD/+gC94CVd4wccm3EpZh 8rVgQLVJRfgOnVBaE/Figd+uuvCCBpaoio/AeGr+4+JN1eB3r7QOetXPUIK9B2+Z CGatTYJG6usERX5sZpVD8nG13b3OOi6FnhLQWgQ= RowId : 1847 ConfigString : dc2.contoso.com\contoso-DC2-CA Table : Request PS C:\>
Here it is. Raw request is base64-encoded (always, when viewing from CA database). We should construct a X509CertificateRequest class by using a X509CertificateRequest( Byte[] ) constructor:
PS C:\> $reqbytes = [convert]::FromBase64String($row."Request.RawRequest") PS C:\> $req = New-Object System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest (,$reqBytes) PS C:\> $req Version : 1 RequestType : PKCS7 Subject : CN=www.contoso.com, OU=Division of IT, O=Contoso Pharmaceuticals SubjectDN : System.Security.Cryptography.X509Certificates.X500DistinguishedName PublicKey : System.Security.Cryptography.X509Certificates.PublicKey Attributes : {0, 0, 0} Extensions : {1.3.6.1.4.1.311.21.8.149510.7314491.15746959.9320746.3700693.37.12674649.13726756 (Web Server V2) , 2.5.29.37 (Enhanced Key Usage), 2.5.29.15 (Key Usage), 2.5.29.32 (Certificate Policies)...} ExternalData : System.Security.Cryptography.Pkcs.PKCS7SignedMessage SignatureIsValid : True SignatureAlgorithm : 1.2.840.113549.1.1.5 (sha1RSA) RawData : {48, 130, 5, 41...} PS C:\>
We can explore $req
object and automate request validation rules. Alternatively, we can dive in to request details by calling ToString method:
PS C:\> $req.ToString() PKCS10 Certificate Request: Version: 1 Subject: CN=www.contoso.com, OU=Division of IT, O=Contoso Pharmaceuticals Public Key Algorithm: Algorithm ObjectId: RSA (1.2.840.113549.1.1.1) Algorithm Parameters: 05 00 Public Key Length: 1024 bits Public Key: UnusedBits=0 0000 30 81 89 02 81 81 00 d4 37 27 43 36 32 2a a8 9c 0010 8c 95 57 8c a0 f9 84 28 1e ec c6 c4 ad 4a 06 93 0020 9f f4 6b 19 d8 44 7f 30 d6 87 f5 e0 fc 7c 92 c1 0030 e5 1c db c1 6c 29 b4 5e 9c 1b ac 70 07 44 60 c8 0040 dd cf 04 23 20 fb 4a 26 0e 55 d4 c5 68 6f 83 04 0050 4a 71 55 a8 c2 fc b2 53 be 36 45 23 5d 85 1f 2f 0060 7c 87 e3 3f 19 02 0e ff 9d 30 ae 28 51 3a 4b ec 0070 73 6c 6d 62 e0 2b 79 15 92 86 00 5f 89 0c 1f 4b 0080 68 51 56 8b 9d d7 b5 02 03 01 00 01 Request attributes (Count=3): Attribute[0], Length=12 (0c): OS Version (OID=1.3.6.1.4.1.311.13.2.3): 6.0.6002.2 Attribute[1], Length=54 (36): Client Info (OID=1.3.6.1.4.1.311.21.20): Client ID: ClientIdDefaultRequest (5) Computer name: dc2.contoso.com User name: CONTOSO\Administrator Process name: MMC.EXE Attribute[2], Length=100 (64): CSP Info (OID=1.3.6.1.4.1.311.13.2.2): KeySpec: 1 Provider: Microsoft RSA SChannel Cryptographic Provider Signature unused bits: 0 Request extensions (Count=6): OID=Certificate Template Information (1.3.6.1.4.1.311.21.7), Critical=False, Length=47 (2f): Template=Web Server V2(1.3.6.1.4.1.311.21.8.149510.7314491.15746959.9320746.3700693.37.12674649.13726756) Major Version Number=100 Minor Version Number=7 OID=Enhanced Key Usage (2.5.29.37), Critical=False, Length=12 (0c): Server Authentication (1.3.6.1.5.5.7.3.1) OID=Key Usage (2.5.29.15), Critical=False, Length=4 (04): Digital Signature, Key Encipherment (a0) OID=Certificate Policies (2.5.29.32), Critical=False, Length=81 (51): [1]Certificate Policy: Policy Identifier=EV [1,1]Policy Qualifier Info: Policy Qualifier Id=CPS Qualifier: http://www.contoso.com OID=Application Policies (1.3.6.1.4.1.311.21.10), Critical=False, Length=14 (0e): [1]Application Certificate Policy: Policy Identifier=Server Authentication OID=Subject Key Identifier (2.5.29.14), Critical=False, Length=22 (16): 5f 84 5f 88 92 af fd 86 20 f8 53 73 a3 e4 c7 e8 15 22 b2 6c Signature Algorithm: Algorithm ObjectId: 1.2.840.113549.1.1.5 (sha1RSA) Signature: Unused bits=0 0000 86 09 38 15 da e8 04 d2 0f 0d 18 da 15 a9 76 af 0010 f4 94 95 16 34 3c c8 67 7b f7 89 24 74 d7 0d c3 0020 5a 4f 3a e0 33 71 89 af e4 2e 4b f5 fa f8 5e c3 0030 08 44 8c 50 ba d0 65 2d 71 80 52 ed 6c 7d 9f 2f 0040 0f 38 83 48 87 32 23 13 30 85 e3 5e 79 36 fa 6b 0050 56 9b a6 6d a3 72 30 7d 1a 3b 6f d7 02 96 a5 fd 0060 39 3c 47 21 77 99 ab 23 54 0c fc 1f f8 8c de 2a 0070 b9 61 e8 ad 11 91 47 6c 2e 56 18 91 39 aa 50 cf Signature matches Public Key: True PS C:\>
This information is enough to ensure whether the request is legitimate or not. In this case, we don't see any suspicious data, so let issue certificate. For these purposes we have Approve-CertificateRequest command:
PS C:\> Get-PendingRequest -CA $ca -RequestID 1847 | Approve-CertificateRequest
The certificate '1847' was issued.'
PS C:\>
call IIS admin and tell them that the certificate is issued and they can retrieve and install in IIS.
Why request review is important? Apply the same techniques to request with ID=1649:
PS C:\> $row = Get-PendingRequest -CA $ca -Property "RawRequest" -RequestID 1849
PS C:\> $reqbytes = [convert]::FromBase64String($row."Request.RawRequest")
PS C:\> $req = New-Object System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest (,$reqBytes)
PS C:\> $req.ToString()
PKCS10 Certificate Request:
Version: 1
Subject:
CN=www.contoso.com
Public Key Algorithm:
Algorithm ObjectId: RSA (1.2.840.113549.1.1.1)
Algorithm Parameters:
05 00
Public Key Length: 1024 bits
Public Key: UnusedBits=0
0000 30 81 89 02 81 81 00 b2 bd 27 6f 03 bb 76 91 3a
0010 e1 28 40 d8 5f fe 9c 32 7e 16 e9 e2 19 fc 70 6c
0020 54 26 fe 86 f6 49 81 71 15 b9 a1 e6 01 1e b6 7c
0030 0a 97 25 ff f4 59 d5 13 34 3d ac 5d ac 23 b6 7a
0040 24 7b c0 5c 64 8d 27 d5 42 01 fb 59 77 9c 77 e5
0050 20 2d c3 53 f0 a3 dd 54 0b 4e 1d f9 07 7a ce 20
0060 12 bf d8 2a b3 6e 42 2c a5 d8 ed e2 68 79 f0 81
0070 25 cc 37 69 c6 56 c0 37 4f 1d cb 99 2b ec ec 52
0080 57 1a 47 2e 22 f5 0b 02 03 01 00 01
Request attributes (Count=3):
Attribute[0], Length=12 (0c):
OS Version (OID=1.3.6.1.4.1.311.13.2.3): 6.0.6002.2
Attribute[1], Length=54 (36):
Client Info (OID=1.3.6.1.4.1.311.21.20):
Client ID: ClientIdDefaultRequest (5)
Computer name: dc2.contoso.com
User name: CONTOSO\Administrator
Process name: MMC.EXE
Attribute[2], Length=100 (64):
CSP Info (OID=1.3.6.1.4.1.311.13.2.2):
KeySpec: 1
Provider: Microsoft RSA SChannel Cryptographic Provider
Signature unused bits: 0
Request extensions (Count=7):
OID=Certificate Template Information (1.3.6.1.4.1.311.21.7), Critical=False, Length=47 (2f):
Template=Web Server V2(1.3.6.1.4.1.311.21.8.149510.7314491.15746959.9320746.3700693.37.12674649.13726756)
Major Version Number=100
Minor Version Number=7
OID=Enhanced Key Usage (2.5.29.37), Critical=False, Length=12 (0c):
Server Authentication (1.3.6.1.5.5.7.3.1)
OID=Key Usage (2.5.29.15), Critical=False, Length=4 (04):
Digital Signature, Key Encipherment (a0)
OID=Certificate Policies (2.5.29.32), Critical=False, Length=81 (51):
[1]Certificate Policy:
Policy Identifier=EV
[1,1]Policy Qualifier Info:
Policy Qualifier Id=CPS
Qualifier:
http://www.contoso.com
OID=Application Policies (1.3.6.1.4.1.311.21.10), Critical=False, Length=14 (0e):
[1]Application Certificate Policy:
Policy Identifier=Server Authentication
OID=Subject Alternative Name (2.5.29.17), Critical=False, Length=36 (24):
DNS Name=www.microsoft.com
DNS Name=microsoft.com
OID=Subject Key Identifier (2.5.29.14), Critical=False, Length=22 (16):
1a 33 0c 21 ee 4d 8e 50 f8 d6 49 56 1f e2 07 47 6d d9 b7 18
Signature Algorithm:
Algorithm ObjectId: 1.2.840.113549.1.1.5 (sha1RSA)
Signature: Unused bits=0
0000 c0 6c db 8a f2 aa ac 8b 9f 90 77 90 89 09 27 e1
0010 e5 23 5a 5a 03 1c ba 87 f3 d1 26 24 df 71 4c dc
0020 19 db 7f f1 f5 8b c9 4a fc 6e fc 42 49 a2 53 db
0030 e0 03 2e 36 59 1e c6 1d 11 5d ad 94 21 81 ac 40
0040 f3 5c c2 74 a9 a1 10 6f d1 8c a5 8d cd 4e c8 a5
0050 81 42 29 26 e4 c2 b1 af f2 ca e3 48 b1 80 2f 22
0060 df 4a f4 43 6e a3 40 e8 95 8d f7 6b 91 25 06 aa
0070 95 04 db 35 66 ee 18 84 bf b0 ff 6d dd 52 26 63
Signature matches Public Key: True
PS C:\>
At first glance, the request looks the same, but...wait, what hell happens in the Subject Alternative Names extension? Does internal SharePoint portal run microsoft.com website? Apparently, no. Should we appove such request? Definitely, no. What to do? For such cases we have Deny-CertificateRequest command:
PS C:\> Get-PendingRequest -CA $ca -Property "RawRequest" -RequestID 1849 | Deny-CertificateRequest Successfully denied request with ID = 1849 PS C:\>
Just to recap commands and techniques we used to achieve current scenario:
Request.RawRequest
by using these commands you can automate pending certificate request management in both, automated or manual way. And everything in a single PowerShell console.
Thank you for putting this together. Yet another tool in my Powershell toolbelt to automate my life. Great work.
PS C:\tmp> $row = Get-PendingRequest -CA $ca -Property "RawRequest" -RequestID 151
PS C:\tmp> $reqbytes = [convert]::FromBase64String($row."Request.RawRequest")
PS C:\tmp> $req = New-Object System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest(,$reqbytes)
PS C:\tmp> $req.ToString()
System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest
Tried from CA itself and output is always "System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest" (Server 2012 R2, PS v5.1)
Output from $req
PS C:\tmp> $req
RequestType : PKCS7
SubjectDn :
ExternalData : SysadminsLV.PKI.Cryptography.X509CertificateRequests.X509CertificateRequestCmc
Version : 1
SubjectName :
Subject :
PublicKey : System.Security.Cryptography.X509Certificates.PublicKey
Extensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid,
System.Security.Cryptography.Oid, System.Security.Cryptography.Oid...}
Attributes : {0, 0, 0}
SignatureAlgorithm : System.Security.Cryptography.Oid
SignatureIsValid : True
RawData : {48, 130, 6, 63...}
Any thought?
PS C:\tmp> $row
RequestID : 151
Request.RequesterName : %Sanitized\Sanitized%
Request.SubmittedWhen : 3/29/2019 1:34:16 AM
Request.CommonName :
CertificateTemplate : 1.3.6.1.4.1.311.21.8.14711400.4002105.6506161.13047349.12019167.65.9391372.2825925
Request.RawRequest : MIIGPwYJKoZIhvcNAQcCoIIGMDCCBiwCAQMxDzANBglghkgBZQMEAgEFADCCBIUG
%Sanitized%
6LIw3iYY+CYxN7uPGH0sSC643A==
CertificateTemplateOid : System.Security.Cryptography.Oid
RowId : 151
ConfigString : %Sanitized\Sanitized%
Table : Request
Properties : {[RequestID, 151], [Request.RequesterName, %Sanitized\Sanitized],
[Request.SubmittedWhen, 3/29/2019 1:34:16 AM], [Request.CommonName, ]...}
These commands doesn't seem to work for PKCS10
What commands don't work with PKCS#10? Can you be more specific and provide details.
I have the same issue as Max, on Windows Server 2016
All the guidance provided in this blog post works fine up until you attempt $req.ToString(). With a PKCS#10 request the output from the command $req.ToString() only yields "System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest". It does not show the verbose details as depicted in your screenshot above.
That is what everyone is wondering about. How do we get the verbose output for a PKCS#10 request?
Try $req.Format(), this should work.
Hi Vadims,
I'm trying to view the SAN of a pending request (that was signed with a 'certificate request agent' certificate and submitted on behalf of another user).
This step errors out for me:
req = New-Object System.Security.Cryptography.X509CertificateRequests.X509CertificateRequest(,$reqbytes)
With the following error:
Exception calling ".ctor" with "1" argument(s): "ASN1 bad tag value met."
I am able to successfully dump the request using 'certutil -dump'; it's only with X509CertificateRequest that I get an error.
Could you kindly look into this?
p.s. X509CertificateRequest works fine if it's a regular CSR that was not signed by a 'certificate request agent'.
(I'm trying to do enroll on behalf here, and need to verify the SAN)
Thank you!
@Peter - does the preceding line look like this?
$ca2newreq = Get-PendingRequest -CertificationAuthority $ca2authority -Property "RawRequest" -RequestID $ca2requests.RequestID
if you don't specify "-Property "RawRequest" -RequestID $ca2requests.RequestID" then i think that's why you're having an issue.
Post your comment:
Comments: