Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2012/04/13/how-to-export-issued-certificates-from-a-ca-programatically-powershell/
Post name: How to export issued certificates from a CA programatically (PowerShell)
Original author: Alejandro Campos Magencio
Posting date: 2012-04-13T05:56:38+00:00


Hi all,

The following sample is a conversion of How to export issued certificates from a CA programatically (C#) sample to PowerShell. It will get all the issued certs in the CA database and copy them to a folder:

#Params 
 $strServer = "myserver"; 
 $strCAName = "myserver-CA"; 
 $strPathForCerts = "c:\test\"; 
 
 # Constants 
 $CV_OUT_BASE64HEADER = 0; 
 $CV_OUT_BINARY = 2; 
 
 # Connecting to the Certificate Authority 
 $objCertView = New-Object -ComObject CertificateAuthority.View
 $objCertView.OpenConnection($strServer + "\" + $strCAName)
 
 # Get a column count and place columns into the view 
 $iColumnCount = $objCertView.GetColumnCount(0)
 $objCertView.SetResultColumnCount($iColumnCount)
 
 # Place each column in the view
 for ($x=0; $x -lt $iColumnCount; $x++)
 {
 $objCertView.SetResultColumn($x)
 } 
 
 # Open the View and reset the row position 
 $objCertViewRow = $objCertView.OpenView(); 
 $objCertViewRow.Reset(); 
 
 # Enumerate Row and Column Information 
 # Rows (one per cert) 
 for ($x = 0; $objCertViewRow.Next() -ne -1; $x++) 
 { 
 # Columns with the info we need 
 $objCertViewColumn = $objCertViewRow.EnumCertViewColumn() 
 while ($objCertViewColumn.Next() -ne -1) 
 { 
 switch ($objCertViewColumn.GetDisplayName()) 
 { 
 "Request ID"
 {
 #Request ID 
 $objValue = $objCertViewColumn.GetValue($CV_OUT_BINARY)
 if ($objValue -ne $null) { 
 $strID = "Request ID " + $objValue
 }
 break
 } 
 
 "Binary Certificate"
 {
 # Binary Certificate 
 $objValue = $objCertViewColumn.GetValue($CV_OUT_BASE64HEADER); 
 if ($objValue -ne $null) { 
 # Write certificate to file 
 $strPath = $strPathForCerts + $strID + ".cer"
 Set-Content $strPath $objValue
 } 
 break
 }
 default 
 {
 }
 } 
 } 
 } 
 
 Write-Host "We are done!`nCerts have been copied to " + $strPathForCerts

I hope it helps.

Regards,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2012/04/04/how-to-export-issued-certificates-from-a-ca-programatically-c/
Post name: How to export issued certificates from a CA programatically (C#)
Original author: Alejandro Campos Magencio
Posting date: 2012-04-04T07:29:46+00:00


Hi all,

The following sample is a simplification of How to get info from client certificates issued by a CA (C#), and gets all the issued certs in the CA database and copies them to a folder:

using System;
 using System.Windows.Forms;
 using System.IO;
 using CERTADMINLib;
 
 …
 
 // Parameters
 string strServer = "myserver";
 string strCAName = "myserver-CA";
 string strPathForCerts = "c:\\test\\";
 
 // Constants
 const int CV_OUT_BASE64HEADER = 0;
 const int CV_OUT_BINARY = 2;
 
 // Variables
 CERTADMINLib.CCertView certView = null;
 CERTADMINLib.IEnumCERTVIEWROW certViewRow = null;
 CERTADMINLib.IEnumCERTVIEWCOLUMN certViewColumn = null;
 int iColumnCount = 0;
 object objValue = null;
 string strID = "";
 StreamWriter objFile = null;
 
 // Connecting to the Certificate Authority
 certView = new CERTADMINLib.CCertView();
 certView.OpenConnection(strServer + "\\" + strCAName);
 
 // Get a column count and place columns into the view
 iColumnCount = certView.GetColumnCount(0);
 certView.SetResultColumnCount(iColumnCount);
 
 // Place each column in the view.
 for (int x = 0; x < iColumnCount; x++)
 {
 certView.SetResultColumn(x);
 }
 
 // Open the View and reset the row position
 certViewRow = certView.OpenView();
 certViewRow.Reset();
 
 // Enumerate Row and Column Information
 
 // Rows (one per cert) 
 for (int x = 0; certViewRow.Next() != -1; x++)
 {
 // Columns with the info we need
 certViewColumn = certViewRow.EnumCertViewColumn();
 while (certViewColumn.Next() != -1)
 {
 switch (certViewColumn.GetDisplayName())
 {
 // Request ID
 case "Request ID":
 objValue = certViewColumn.GetValue(CV_OUT_BINARY);
 if (objValue != null)
 {
 strID = "Request ID " + objValue.ToString();
 }
 break;
 
 // Binary Certificate
 case "Binary Certificate":
 objValue = certViewColumn.GetValue(CV_OUT_BASE64HEADER);
 if (objValue != null)
 {
 // Write certificate to file
 objFile = File.CreateText(strPathForCerts + strID + ".cer");
 objFile.Write(objValue.ToString());
 objFile.Close(); 
 }
 break;
 
 default:
 break;
 }
 }
 }
 
 MessageBox.Show("We are done!\nCerts have been copied to " + strPathForCerts);

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2012/04/04/how-to-get-info-from-client-certificates-issued-by-a-ca-c-vs-2010/
Post name: How to get info from client certificates issued by a CA (C#, VS 2010)
Original author: Alejandro Campos Magencio
Posting date: 2012-04-04T07:24:26+00:00


Hi all,

 

I developed this sample some time ago: How to get info from client certificates issued by a CA (C#). The other day I tried it on a new machine with Windows 7, Visual Studio 2010 and .NET Framework 4.0, and it didn't even compile. I had to do the following to make it work:

1) Install thisto be able to usecertadmin.dll in a client machine:

Remote Server Administration Tools for Windows 7 with Service Pack 1 (SP1)

Or this depending on your OS version:

Microsoft Remote Server Administration Tools for Windows Vista

And turn the feature on from "Control Panel" > "Programs and Features" > "Turn Windows features on or off".

2) Generate certadminlib.dll with "tlbimp certadm.dll" and add it as a reference to the project.

3) Change this

CERTADMINLib.CCertViewClass

to this:

CERTADMINLib.CCertView

4) Add Microsoft.CSharp reference.

 

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2012/03/09/why-is-my-process-in-a-job-if-i-didnt-put-it-there/
Post name: Why is my process in a Job if I didn’t put it there?
Original author: Alejandro Campos Magencio
Posting date: 2012-03-09T06:06:00+00:00


Hi all,

The other day a customer of mine was having this issue on Windows 7: CreateProcessAsUser fails with error 5 (Access Denied) when using Jobs. So he had a Windows service running as System in Session 0, that service created a process running as System in Session 0 too, and this process tried to create a new process in logged-on user's session but failed with Access Denied. The process that the service created as System in Session 0 was member of a Job and that was the cause of the issue as my other post explains.

Now, my customer confirmed me that he wasn't explicitly adding the process to a Job. Actually, he wasn't using Jobs at all in his app. Why was the process a member of a Job then?

According to the Job Objects documentation, a process is associated to a Job either explicitly via AssignProcessToJobObject API or by default if your parent process is part of a Job already. In my customer's scenario, his Windows service was not part of a Job, and he wasn't calling any Job API in his code.

I did some kernel debugging to figure out who was assigning that process to a Job, and I found it. Our Program Compatibility Assistant Service (PcaSvc) was the process calling AssignProcessToJobObjectto do the task.

Our Program Compatibility Assistant (PCA) service got the details of customer's app and the Job from an LRPC (Local Remote Procedure Call) call made from customer's Windows Service. But customer's code was not doing this directly. This was something that was happening behind the scenes when the service was creating the problematic process.

What is PCA?

Program Compatibility Assistant: frequently asked questions

What is the Program Compatibility Assistant?
The Program Compatibility Assistant detects known compatibility issues in older programs.

What changes does it make?
It depends on the problem, but any changes made are related to how Windows runs the program. No changes are made to the program itself. For example, the Program Compatibility Assistant can resolve conflicts with User Account Control, a new security feature in this version of Windows that can help make your computer safer. Or, it can run the program in a mode that simulates earlier versions of Windows. The changes that Program Compatibility Assistant makes are done automatically, so you don't need to make them.

How do I turn it off or turn it back on?
Adjustments to the Program Compatibility Wizard can be made by using Group Policy. For more information on how to use Group Policy, go to the Microsoft website for IT professionals.
The Program Compatibility Assistant is an automatic feature of Windows that runs when it detects an older program has a compatibility problem.

Doing some research I found out that, by design, PCA uses Job objects to perform its tasks. So PCA is clearly interfering with the problematic process. It detected some sort of compatibility problem with it, run it in compatibility mode and assigned it to aJob to handle it.

There are several ways to exclude programs from the PCA:

Program Compatibility Assistant (PCA) in Windows Vista

Excluding Programs from PCA

PCA is intended to detect issues with older programs and not intended to monitor programs developed for Windows Vista and Windows Server 2008. The best option to exclude a program from PCA is to include, with the program, an application manifest with run level (either Administrator or as limited users) marking for UAC. This marking means the program is tested to work under UAC (and Windows Vista and Windows Server 2008). PCA checks for this manifest and will exclude the program. This process applies for both installer and regular programs.

Another option to exclude applications from PCA is to add the list of executable files with full path under the following registry key: HKEY_LOCAL_MACHINE\ Software\Microsoft\Windows NT\CurrentVersion\Compatibility Assistant. The value name is ExecutablesToExclude, which is type REG_MULTI_SZ.

PCA automatically excludes programs running from network locations and programs containing fixes applied to them in the application compatibility databases.

A group policy setting is provided to disable PCA for all programs if desired. The name of the policy is Turn Off Program Compatibility Assistant. It can be found under Administrative Templates\Windows Components\Application Compatibility in the group policy editor (gpedit.msc).

There are also individual policies to turn off specific scenarios. These policies are available under Administrative Templates\System\Troubleshooting and Diagnostics\Application Compatibility Diagnostics in the group policy editor.

So just to test my findings were correct, I did a quick test: I added the path to the problematic EXE to the REG_MULTI_SZ value ExecutablesToExclude I created under HKEY_LOCAL_MACHINE\ Software\Microsoft\Windows NT\CurrentVersion\Compatibility Assistant, and it worked! The problematic process was not assigned to a Job anymore, and I didn't get the Access Denied error.

 

Summing up, there are several ways to solve this issue:
1)Problematic process creates its child processes with CREATE_BREAKAWAY_FROM_JOB, so we don’t care if it is within a Job or not.
2)We exclude the problematic process from PCA via registry or GPO.
3)We add a UAC manifest to problematic process. (For example: Step 6: Create and Embed an Application Manifest (UAC)).

 

My customer already had a manifest in his problematic process, but he had to add a Compatibility section (see Application Manifest for details) to make things work on Windows 7:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!--The ID below indicates application support for Windows Vista -->
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
            <!--The ID below indicates application support for Windows 7 -->
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
        </application>
    </compatibility>
</assembly>

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2012/03/09/createprocessasuser-fails-with-error-5-access-denied-when-using-jobs/
Post name: CreateProcessAsUser fails with error 5 (Access Denied) when using Jobs
Original author: Alejandro Campos Magencio
Posting date: 2012-03-09T02:03:54+00:00


Hi all,

The other day I worked on a support case where a Windows service running as System in Session 0 was creating a processalso running as System in Session 0, and this new process failed to create another process in the logged-on user's session (Session 2 in this particular case). And it failed because CreateProcessAsUser API didn't work and returned error 5 (Access Denied).

Note the issue happened on Windows 7, and because of Session 0 Isolation the logged-on user and the service (and its child process running as System) were running in different sessions.

 

To understand what was going on exactly, I did some kernel debugging of the issue and saw that the error in CreateProcessAsUser happened when trying to bind the process we were trying to spawn to its parent's Job (the Job that the process that the service spawned as System was a member of).

Indeed, I could verify with Process Explorer that the process running as System in Session 0 was member of a Job, by checking the properties of the process and going to the Job tab (note: when there is no Job, there is no Job tab).

After a process is associated with a job, by default any child processes it creates are also associated with the job (see Job Objects for more details on this).

But the following is also documented:

AssignProcessToJobObject function

Terminal Services: All processes within a job must run within the same session as the job.

Which means that, as the new process we are trying to create is in a different session than its parent, we will fail to bind it to its parent's Job.

The only way to work around this, would be to create the process in the different session by passing this flag to the CreateProcessAsUser API: Process Creation Flags

CREATE_BREAKAWAY_FROM_JOB

0x01000000 The child processes of a process associated with a job are not associated with the job.
If the calling process is not associated with a job, this constant has no effect. If the calling process is associated with a job, the job must set the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit.

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)