﻿<?xml version="1.0" encoding="UTF-8"?>
<!--RSS generated by Windows SharePoint Services V3 RSS Generator on 2012.05.19. 0:43:07-->
<?xml-stylesheet type="text/xsl" href="/_layouts/RssXslt.aspx?List=332991f0-bfed-4143-9eea-f521167d287c" version="1.0"?>
<rss version="2.0">
  <channel>
    <title>Уютненький бложик: Posts</title>
    <link>http://en-us.sysadmins.lv/Lists/Posts/AllPosts.aspx</link>
    <description>RSS feed for the Posts list.</description>
    <copyright>Vadims Podans (en-us.sysadmins.lv)</copyright>
    <lastBuildDate>Fri, 18 May 2012 20:43:07 GMT</lastBuildDate>
    <generator>Windows SharePoint Services V3 RSS Generator</generator>
    <ttl>60</ttl>
    <image>
      <title>PowerShell Crypto Guy's weblog: Posts</title>
      <url>/_layouts/images/homepage.gif</url>
      <link>http://en-us.sysadmins.lv/Lists/Posts/AllPosts.aspx</link>
    </image>
    <item>
      <title>You cannot submit a certificate request generated by Exchange Management Console (EMC) or Exchange Management Shell (EMS) to Microsoft Certificate Services</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=68</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass7CDC300736FF4128971D68017FE6C9F5><h5><strong>SYMPTOMS</strong></h5> <p>Consider the following scenario. You create certificate certificate by using either Exchange Management Console (<strong>EMC</strong>) or Exchange Management Shell (<strong>EMS</strong>) and save it to a file. When you attempt to submit certificate request to a Windows-based Certification Authority (<strong>CA</strong>) (also known as Microsoft Certificate Services), you may receive error message. If CA server runs on Windows Server 2003 (R2) or Windows Server 2008, you receive the following message:</p> <p align=center><img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px" title="ASN1 bad tag value met. 0x8009310b (ASN: 267)" border=0 alt="ASN1 bad tag value met. 0x8009310b (ASN: 267)" src="/Lists/Posts/Attachments/68/image_17161ed3-f994-4e7e-a629-4f7981849a05_47B2BB4E.png" width=342 height=149></p> <blockquote><pre><font color="#ff0000">ASN1 bad tag value met. 0x8009310b (ASN: 267).</font></pre></blockquote>
<p>If CA server runs on Windows Server 2008 R2, no there are no response from MMC console. If you are using <strong>certreq.exe</strong> utility, you receive an error:</p>
<blockquote><pre>Contoso Pharmaceuticals Enrollment Policy
  {F29AC102-CDCD-4AA8-B1F5-761051FB52C5}
  https://cert.contoso.com/ADPolicyProvider_CEP_Kerberos/service.svc/CEP
<font color="#ff0000">Certificate not issued (Incomplete)</font></pre></blockquote>
<p>And certificate request is not issued, failed or pended.</p>
<p><strong>Additional information:</strong> for certificate request generation follow the steps described in the  <a href="http://technet.microsoft.com/en-us/library/dd351057.aspx">Create a New Exchange Certificate</a> TechNet article.</p>
<p><strong>Aside note:</strong> certificate request do not contains certificate template information which is required for Enterprise CAs. In order to submit the request to Enteprise CA you should use <strong>certreq.exe</strong> utility with the following syntax:</p>
<blockquote><pre>certreq –submit –attrib &quot;CertificateTemplate:<em>TemplateCommonName</em>&quot;</pre></blockquote>
<p>this command will add certificate template information as a attribute.</p><strong>
<hr>

<h5>CAUSE</h5></strong>
<p>This behavior occurs when certificate request is stored in a file in Unicode encoding. Microsoft Certificate Services do not support Unicode-encoded files request files. Only ANSI encoding is supported. 
<hr>

<h5>STATUS</h5>
<p>Microsoft has confirmed this behavior as inconsistent. No bug fixes are available. See <strong>Workaround</strong> section for example steps to overcome the issue. 
<hr>

<h5>WORKAROUND</h5>
<ol>
<li>If you already have certificate request file, do the following: 
<ul>
<li>Open <strong>Notepad</strong> program. 
<li>In the <strong>File</strong> menu, click <strong>Open</strong>. 
<li>In the <strong>Open File</strong> dialog, locate certificate request file. 
<li>In the <strong>File</strong> menu, click <strong>Save As…</strong> option. 
<li>Type a name for new request file. In the <strong>Encoding</strong> drop-down list, select <strong>ANSI</strong>. 
<li>Click <strong>Save</strong> to save the request. 
<li>Now you can resubmit certificate request to Microsoft Certificate Services</li></ul>
<li>If you are using Exchange Management Shell use the following guidance to save Base64-encoded certificate request to a file with proper encoding:</li></ol>
<p>In the Exchange Management Shell console run <a href="http://technet.microsoft.com/en-us/library/aa998327.aspx">New-ExchangeCertificate</a> cmdlet with required parameters, save output to a variable and save output to a file with proper encoding:</p>
<blockquote><pre><span style="color:#800080">$OutputRequest</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> <span style="color:#5f9ea0;font-weight:bold">New-ExchangeCertificate</span> &lt;Specify and fill all required properties&gt;
</span><span style="color:#5f9ea0;font-weight:bold">Set-Content</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Path</span><span style="color:#000000"> </span><span style="color:#800000">Path\ExchRequest</span><span style="color:#000000">.req </span><span style="font-style:italic;color:#5f9ea0">-Value</span><span style="color:#000000"> </span><span style="color:#800080">$OutputRequest</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Encoding</span><span style="color:#000000"> </span><span style="color:#800000">ANSI</span></pre></blockquote>
<p>The default behavior for PowerShell <a href="http://technet.microsoft.com/en-us/library/dd347736.aspx">Set-Content</a>, <a href="http://technet.microsoft.com/en-us/library/dd347594.aspx">Add-Content</a>, <a href="http://technet.microsoft.com/en-us/library/dd315303.aspx">Out-File</a> and <a href="http://technet.microsoft.com/en-us/library/dd315283.aspx">redirection operator</a> &quot;<strong>&gt;</strong>&quot; is to save content in Unicode encoding. If the file already exist, the commands respects existing file encoding. The default encoding can be changed by using <strong>–Encoding</strong> parameter for cmdlets.</p>
<p><strong><font color="#ff0000">Note:</font></strong> redirection operators do not support encoding change.</p>
<p>
<hr>

<h5>APPLIES TO</h5>
<ul>
<li>Windows Server 2003 (x86 and x64) Standard, Enterprise and Datacenter editions, all service packs 
<li>Windows Server 2003 (x86 and x64) R2 Standard, Enterprise and Datacenter editions, all service packs 
<li>Windows Server 2008 (x86 and x64) Standard, Enterprise and Datacenter editions, all service packs 
<li>Windows Server 2008 R2 Standard, Enterprise and Datacenter editions, all service packs 
<li>Active Directory Certificate Services
<li>Microsoft Exchange Server 2007
<li>Microsoft Exchange Server 2010</li></ul></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2012.04.19. 22:46</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/68/image_17161ed3-f994-4e7e-a629-4f7981849a05_47B2BB4E.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/68/image_17161ed3-f994-4e7e-a629-4f7981849a05_47B2BB4E.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Thu, 19 Apr 2012 19:46:05 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=68</guid>
    </item>
    <item>
      <title>How to register custom Object Identifier</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=67</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassEF566FDE6B7C48FCBD5A2142833862AB><p>Today I will discuss about how to register custom object identifier on a local computer. Why you need this? .NET <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.oid.aspx">Oid</a> class which can resolve many common object identifiers to their friendly names and vice versa. However, not all OIDs are registered there. For example, RDS (Remote Desktop Services, former Terminal Services) team introduces special OID for RDP-SSL enhanced key usage with OID=1.3.6.1.4.1.311.54.1.2:</p> <p><img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/67/image_57a0858f-67d6-463a-99ae-32c3fac412c6_5F5ED9AD.png" width=421 height=177></p> <p>If you have Active Directory domain and at least one Enterprise CA, you can define this OID in Active Directory (by editing certificate template). But what if you don't have Active Directory or internal Enterprise CA? Then PowerShell and CryptoAPI is the answer here!</p> <p>Looking to a CryptoAPI unmanaged functions we can find this one: <a href="http://msdn.microsoft.com/en-us/library/aa380267(VS.85).aspx">CryptRegisterOIDInfo</a>. This function writes OID=Friendly Name association to system registry and allows to overwrite existing bindings (see <em>dwFlags</em> parameter description)! Since the first OID=Friendly Name association is returned, you can set this parameter to <strong>CRYPT_INSTALL_OID_INFO_BEFORE_FLAG</strong> (0x1) and overwrite existing bindings.</p> <p>At first we need to define p/invoke signature definitions for <a href="http://msdn.microsoft.com/en-us/library/aa380267(VS.85).aspx">CryptRegisterOIDInfo</a> and <a href="http://msdn.microsoft.com/en-us/library/aa380907(VS.85).aspx">CryptUnregisterOIDInfo</a> functions (to delete OID definitions). Additionally we need to define <a href="http://msdn.microsoft.com/en-us/library/aa381435(VS.85).aspx">CRYPT_OID_INFO</a> structure definition. And they are:</p> <blockquote><pre><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[SecurityCritical]
[DllImport(&quot;Crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptRegisterOIDInfo(
    CRYPT_OID_INFO pInfo,
    int dwFlags
);
[SecurityCritical]
[DllImport(&quot;Crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptUnregisterOIDInfo(
    CRYPT_OID_INFO pInfo
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CRYPT_OID_INFO {
    public int cbSize;
    [MarshalAs(UnmanagedType.LPStr)]
    public string pszOID;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string pwszName;
    public int dwGroupId;
    // actually this is a Union, but at this point we don't care about this
    public int dwValue;
    public CRYPTOAPI_BLOB ExtraInfo;
    // for compatibility purposes I'm using structure definition that is supported by
    // Windows XP/Windows Server 2003 (without CNG algorithms).
    // Uncomment the block below if necessary:
    // [MarshalAs(UnmanagedType.LPWStr)]
    // public string pwszCNGAlgid;
    // [MarshalAs(UnmanagedType.LPWStr)]
    // public string pwszCNGExtraAlgid;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPTOAPI_BLOB {
    public UInt32 cbData;
    public IntPtr pbData;
}
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Crypt32</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-UsingNamespace</span><span style="color:#000000"> </span><span style="color:#800000">System.Security</span></pre></blockquote>
<p>The minimum required information for <a href="http://msdn.microsoft.com/en-us/library/aa381435(VS.85).aspx">CRYPT_OID_INFO</a> structure is:</p>
<ul>
<li><em>cbSize</em> — the unmanaged size of the structure. The size can be retrieved by using <a href="http://msdn.microsoft.com/en-us/library/5s4920fa.aspx">Marshal.SizeOf</a> static method; 
<li><em>pszOID</em> — an object identifier string; 
<li><em>pwszName</em> — a friendly name associated with the OID; 
<li><em>dwGroupId</em> — since our OID is EKU OID, we will use <strong>CRYPT_ENHKEY_USAGE_OID_GROUP_ID</strong> (0x6).</li></ul>
<p>And here we go:</p>
<p><strong><font color="#ff0000">Note:</font></strong> you must use elevated PowerShell console (with local administrator permissions).</p>
<blockquote><pre><span style="color:#800080">$oidInfo</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">PKI.Crypt32</span><span style="color:#000000">+CRYPT_OID_INFO </span><span style="font-style:italic;color:#5f9ea0">-Property</span><span style="color:#000000"> @{
    cbSize </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">SizeOf</span><span style="color:#000000">([</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">+CRYPT_OID_INFO]);
    pszOID </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">1.3.6.1.4.1.311.54.1.2</span><span style="color:#800000">&quot;</span><span style="color:#000000">;
    pwszName </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Remote Desktop Authentication</span><span style="color:#800000">&quot;</span><span style="color:#000000">;
    dwGroupId </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">6</span><span style="color:#000000">;
}
[</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptRegisterOIDInfo</span><span style="color:#000000">(</span><span style="color:#800080">$oidInfo</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)
</span><span style="color:#008000">#</span><span style="color:#008000"> unregister OID</span><span style="color:#008000">
</span><span style="color:#000000">[</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptUnregisterOIDInfo</span><span style="color:#000000">(</span><span style="color:#800080">$oidInfo</span><span style="color:#000000">)</span></pre></blockquote>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#00ff00">[↑]</font> [system32] $oidInfo = New-Object PKI.Crypt32+CRYPT_OID_INFO -Property @{
&gt;&gt;     cbSize = [Runtime.InteropServices.Marshal]::SizeOf([PKI.Crypt32+CRYPT_OID_INFO]);
&gt;&gt;     pszOID = &quot;1.3.6.1.4.1.311.54.1.2&quot;;
&gt;&gt;     pwszName = &quot;Remote Desktop Authentication&quot;;
&gt;&gt;     dwGroupId = 6;
&gt;&gt; }
&gt;&gt;
<font color="#00ff00">[↑]</font> [system32] [PKI.Crypt32]::CryptRegisterOIDInfo($oidInfo,0)
True</p></span></font></pre></blockquote></div>
<p>If the function returns True, then everything is ok:</p>
<p><img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/67/image_b08b843d-4538-4a00-946f-539d60746ed2_4A6D573A.png" width=421 height=191></p>
<p>The only note here is that OID information may not work immediately and may require to restart PowerShell console. This is because, existing PowerShell console already has OID information in memory and new registered OIDs are not there. But for any new PS windows, a new information is available:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] [System.Security.Cryptography.Oid]&quot;1.3.6.1.4.1.311.54.1.2&quot;

Value                                                       FriendlyName
-----                                                       ------------
1.3.6.1.4.1.311.54.1.2                                      Remote Desktop Authentication


<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>Use the same structure to unregister the OID:</p>
<blockquote><pre><span style="color:#000000">[</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptUnregisterOIDInfo</span><span style="color:#000000">(</span><span style="color:#800080">$oidInfo</span><span style="color:#000000">)</span></pre></blockquote>
<p>In this way you can register any OIDs and OID types you need.</p>
<p>HTH.</p></div></div>
<div><b>Category:</b> PowerShell;CryptoAPI</div>
<div><b>Published:</b> 2012.04.15. 15:17</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/67/image_57a0858f-67d6-463a-99ae-32c3fac412c6_5F5ED9AD.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/67/image_57a0858f-67d6-463a-99ae-32c3fac412c6_5F5ED9AD.png</a><br><a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/67/image_b08b843d-4538-4a00-946f-539d60746ed2_4A6D573A.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/67/image_b08b843d-4538-4a00-946f-539d60746ed2_4A6D573A.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PowerShell;CryptoAPI</category>
      <pubDate>Sun, 15 Apr 2012 12:17:09 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=67</guid>
    </item>
    <item>
      <title>Digging into digital signatures (part 2)</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=66</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass915D46ED267345039DADD003CF0AD5BA><p>In <a href="/Lists/Posts/Post.aspx?ID=65">previous post</a> we talked about digital signatures and how we can verify them in PowerShell (RSA signatures). I promised to continue this diving with unmanaged stuff.</p> <p>As we already discussed, CryptoAPI has unmanaged structure <a href="http://msdn.microsoft.com/en-us/library/aa377540(VS.85).aspx">CERT_SIGNED_CONTENT_INFO</a> which represents a signed info, including actual data to be signed, algorithm identifier and signature value. In order to deal with this structure we need to use some encoders and decoders. In the decoding process a ASN.1-encoded raw byte array is converted to a structure and in encoding process, a structure is converted to a ASN.1-encoded byte array. CryptoAPI contains 2 (actually 4) functions for ASN.1 encoding/decoding:</p> <ul> <li><a href="http://msdn.microsoft.com/en-us/library/aa379911(VS.85).aspx">CryptDecodeObject</a> (<a href="http://msdn.microsoft.com/en-us/library/aa379912(VS.85).aspx">CryptDecodeObjectEx</a>);  <li><a href="http://msdn.microsoft.com/en-us/library/aa379921(VS.85).aspx">CryptEncodeObject</a> (<a href="http://msdn.microsoft.com/en-us/library/aa379922(VS.85).aspx">CryptEncodeObjectEx</a>).</li></ul> <p>Also we will have to define related structures (of which consist <a href="http://msdn.microsoft.com/en-us/library/aa377540(VS.85).aspx">CERT_SIGNED_CONTENT_INFO</a> structure):</p> <ul> <li><a href="http://msdn.microsoft.com/en-us/library/aa381414(VS.85).aspx">CRYPT_INTEGER_BLOB</a> (known as CRYTPTOAPI_BLOB)  <li><a href="http://msdn.microsoft.com/en-us/library/aa381133(VS.85).aspx">CRYPT_ALGORITHM_IDENTIFIER</a>  <li><a href="http://msdn.microsoft.com/en-us/library/aa381165(VS.85).aspx">CRYPT_BIT_BLOB</a></li></ul> <p>I assume that you have at least basic experience with P/Invoke and dealing with unknown length data.</p> <p><strong><font color="#ff0000">Note:</font></strong> what does means the data with unknown length? In certain cases, unmanaged function cannot determine the resulting size of the output value. Therefore, the function is called twice: first time with empty buffer (which receives the data) and function returns required buffer size. Then you allocate the buffer (with enough size) and specify this buffer during second call. And function will export resulted data. For more details you can check the following MSDN article: <a href="http://msdn.microsoft.com/en-us/library/aa387677(VS.85).aspx">Retrieving Data of Unknown Length</a>.</p> <p>At first we need to write a definitions for <a href="http://msdn.microsoft.com/en-us/library/aa379911(VS.85).aspx">CryptDecodeObject</a> function and related structures:</p> <blockquote><pre><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[DllImport(&quot;Crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptDecodeObject(
    UInt32 dwCertEncodingType,
    UInt32 lpszStructType,
    IntPtr pbEncoded,
    UInt32 cbEncoded,
    UInt32 dwFlags,
    IntPtr pvStructInfo,
    ref    UInt32 pcbStructInfo
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CERT_SIGNED_CONTENT_INFO {
    public CRYPTOAPI_BLOB ToBeSigned;
    public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
    public CRYPT_BIT_BLOB Signature;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPTOAPI_BLOB {
    public UInt32 cbData;
    public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_ALGORITHM_IDENTIFIER {
    [MarshalAs(UnmanagedType.LPStr)]
    public String pszObjId;
    public CRYPTOAPI_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_BIT_BLOB {
    public UInt32 cbData;
    public IntPtr pbData;
    public UInt32 cUnusedBits;
}
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Crypt32</span></pre></blockquote>
<p>In the next examples we will convert ASN.1-encoded byte array and use <a href="http://msdn.microsoft.com/en-us/library/aa379911(VS.85).aspx">CryptDecodeObject</a> function to split this array to a signing parts (tbs data, algorithm identifier and signature).</p>
<p><strong><font color="#ff0000">Note:</font></strong> use <a href="http://msdn.microsoft.com/en-us/library/aa378145(VS.85).aspx">Constants for CryptEncodeObject and CryptDecodeObject</a> page for structure identifiers which will be passed to <em>lpszStructType</em> parameter. In our case, <a href="http://msdn.microsoft.com/en-us/library/aa377540(VS.85).aspx">CERT_SIGNED_CONTENT_INFO</a>.</p>
<p>In the first <a href="http://msdn.microsoft.com/en-us/library/aa379911(VS.85).aspx">CryptDecodeObject</a> call we specify the following parameters:</p>
<ul>
<li><em><font color="#0000ff">dwCertEncodingType</font></em> = 65537 (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING); 
<li><em><font color="#0000ff">lpszStructType</font></em> = 1 (as integer, not a string); 
<li><em><font color="#0000ff">pbEncoded</font></em> = raw encoded byte array (we will use <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.rawdata.aspx">RawData</a> property from <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx">X509Certificate2</a> object); 
<li><em><font color="#0000ff">cbEncoded</font></em> = the length in bytes of raw array; 
<li><em><font color="#0000ff">dwFlags</font></em> = <strong>CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG (0x8)</strong>. We need to specify this flag, because CryptoAPI uses little-endian byte ordering, but .NET — big-endian; 
<li><em><font color="#0000ff">pvStructInfo</font></em> = <a href="http://msdn.microsoft.com/en-us/library/system.intptr.zero.aspx">IntPtr.Zero</a> (with the first call we just determine resulting structure size). 
<li><em><font color="#0000ff">pcbStructInfo</font></em> = reference parameter. We need to define variable that will receive the size before we call the function.</li></ul>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] # retrieve X509Certificate2 object
<font color="#ff0000">[↓]</font> [vPodans] $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 .\Desktop\digicert.cer
<font color="#ff0000">[↓]</font> [vPodans] # extract raw byte array
<font color="#ff0000">[↓]</font> [vPodans] $raw = $cert.RawData
<font color="#ff0000">[↓]</font> [vPodans] # define variable that will receive resulting structure size
<font color="#ff0000">[↓]</font> [vPodans] $pcbStructInfo = 0
<font color="#ff0000">[↓]</font> [vPodans] # call the function to determine resulting structure size
<font color="#ff0000">[↓]</font> [vPodans] [pki.crypt32]::CryptDecodeObject(65537,1,$raw,$raw.length,0x8,[IntPtr]::Zero,[ref]$pcbStructInfo)
True
<font color="#ff0000">[↓]</font> [vPodans] # function returns True (success) and we can check required size:
<font color="#ff0000">[↓]</font> [vPodans] $pcbStructInfo
1760
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>Now we need to allocate the buffer to receive the structure. Since unmanaged code cannot access managed memory, we need to allocate the buffer in unmanaged memory. For memory allocation we will use <a href="http://msdn.microsoft.com/en-us/library/5cyb68cy.aspx">AllocHGlobal</a> method in <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.aspx">InteropServices.Marshal</a> class:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $pvStructInfo = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($pcbStructInfo)
<font color="#ff0000">[↓]</font> [vPodans] $pvStructInfo
43069792
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>We have a pointer. Now we call the <a href="http://msdn.microsoft.com/en-us/library/aa379911(VS.85).aspx">CryptDecodeObject</a> function again with the only change: in pvStructInfo we specify pointer to a allocated memory:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] [pki.crypt32]::CryptDecodeObject(65537,1,$raw,$raw.length,0x8,$pvStructInfo,[ref]$pcbStructInfo)
True
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>Now decoded structure is copied to allocated memory buffer. And how to extract it??? <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.aspx">Marshal</a> class has <a href="http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx">PtrToStructure</a> method which will copy structure from unmanaged memory to a managed structure:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $struct = [System.Runtime.InteropServices.Marshal]::PtrToStructure($pvStructInfo,[PKI.Crypt32+CERT_SIGNED_
CONTENT_INFO])
<font color="#ff0000">[↓]</font> [vPodans] $struct

ToBeSigned                              SignatureAlgorithm                      Signature
----------                              ------------------                      ---------
PKI.Crypt32+CRYPTOAPI_BLOB              PKI.Crypt32+CRYPT_ALGORITHM_IDENTIFIER  PKI.Crypt32+CRYPT_BIT_BLOB


<font color="#ff0000">[↓]</font> [vPodans] $struct.ToBeSigned

                                                     cbData                                                      pbData
                                                     ------                                                      ------
                                                       1404                                                    43069856


<font color="#ff0000">[↓]</font> [vPodans] $struct.SignatureAlgorithm

pszObjId                                                    Parameters
--------                                                    ----------
1.2.840.113549.1.1.5                                        PKI.Crypt32+CRYPTOAPI_BLOB


<font color="#ff0000">[↓]</font> [vPodans] $struct.Signature

                                 cbData                                  pbData                             cUnusedBits
                                 ------                                  ------                             -----------
                                    256                                43071296                                       0


<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>We see that our structure is filled with the data (at first look it looks as not what we expected, wait few minutes).</p>
<p><strong>ToBeSigned</strong> property has two sub properties (inner CRYTPOAPI_BLOB), <strong>cbData</strong> and <strong>pbData</strong>. <strong>pbData</strong> is a pointer to a data to be signed. <strong>cbData</strong> is the size in bytes of the data contained in <strong>pbData</strong>. With <a href="http://msdn.microsoft.com/en-us/library/ms146631.aspx">Marshal.Copy</a> we can copy byte array (without any transformation) to a managed byte array. Again, we need to allocate the buffer to receive the data. But now we need to allocate it in managed memory (because we no longer work with unmanaged functions):</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $tbsData = New-Object byte[] -ArgumentList $struct.ToBeSigned.cbData
<font color="#ff0000">[↓]</font> [vPodans] [System.Runtime.InteropServices.Marshal]::Copy($struct.ToBeSigned.pbData,$tbsData,0,$tbsData.Length)
<font color="#ff0000">[↓]</font> [vPodans] $tbsData[0..5]
48
130
5
120
160
3
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>And we repeat this trick with signature structure:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $signature = New-Object byte[] -ArgumentList $struct.Signature.cbData
<font color="#ff0000">[↓]</font> [vPodans] [System.Runtime.InteropServices.Marshal]::Copy($struct.Signature.pbData,$signature,0,$signature.Length)
<font color="#ff0000">[↓]</font> [vPodans] $signature[0..5]
9
94
76
81
68
128
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>And what next? We missed signature algorithm:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $algorithm

Value                                                       FriendlyName
-----                                                       ------------
1.2.840.113549.1.1.5                                        sha1RSA


<font color="#ff0000">[↓]</font> [vPodans] $algorithm = (New-Object System.Security.Cryptography.Oid $struct.SignatureAlgorithm.pszObjId).FriendlyNam
e
<font color="#ff0000">[↓]</font> [vPodans] # remove 'RSA' suffix to leave only algorithm name
<font color="#ff0000">[↓]</font> [vPodans] $algorithm = $algorithm.Replace(&quot;RSA&quot;,$null)
<font color="#ff0000">[↓]</font> [vPodans] $algorithm
sha1
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>And now we can verify signature with <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.verifydata.aspx">RSACryptoServiceProvider.VerifyData</a> method:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $pubkey = $issuer.PublicKey.Key
<font color="#ff0000">[↓]</font> [vPodans] $pubkey.VerifyData($tbsData,$algorithm,$signature)
True
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>Wow, here we go! Signature was verified successfully!</p>
<p>And the last note: when we finish our stuff, we must release unmanaged buffer. Buffer is allocated by <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.freehglobal.aspx">FreeHGlobal</a> method:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] [System.Runtime.InteropServices.Marshal]::FreeHGlobal($pvStructInfo)</p></span></font></pre></blockquote></div>
<p>And here is PowerShell example which verifies whether the certificate was signed by other certificate's public key:</p>
<blockquote><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Test-CertificateSignature</span><span style="color:#000000"> {
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [</span><span style="color:#008080">Security.Cryptography.X509Certificates.X509Certificate2</span><span style="color:#000000">]</span><span style="color:#800080">$target</span><span style="color:#000000">,
        [</span><span style="color:#008080">Security.Cryptography.X509Certificates.X509Certificate2</span><span style="color:#000000">]</span><span style="color:#800080">$issuer</span><span style="color:#000000">
    )
</span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[DllImport(&quot;Crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptDecodeObject(
    UInt32 dwCertEncodingType,
    UInt32 lpszStructType,
    Byte[] pbEncoded,
    UInt32 cbEncoded,
    UInt32 dwFlags,
    IntPtr pvStructInfo,
    ref UInt32 pcbStructInfo
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CERT_SIGNED_CONTENT_INFO {
    public CRYPTOAPI_BLOB ToBeSigned;
    public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
    public CRYPT_BIT_BLOB Signature;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPTOAPI_BLOB {
    public UInt32 cbData;
    public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_ALGORITHM_IDENTIFIER {
    [MarshalAs(UnmanagedType.LPStr)]
    public String pszObjId;
    public CRYPTOAPI_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct CRYPT_BIT_BLOB {
    public UInt32 cbData;
    public IntPtr pbData;
    public UInt32 cUnusedBits;
}
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Crypt32<br></span><span style="color:#000000">    </span><span style="color:#800080">$raw</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$target</span><span style="color:#000000">.RawData
</span><span style="color:#000000">    </span><span style="color:#800080">$pcbStructInfo</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0<br></span><span style="color:#000000">    [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">pki.crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptDecodeObject</span><span style="color:#000000">(</span><span style="color:#000000">65537</span><span style="color:#000000">,</span><span style="color:#000000">1</span><span style="color:#000000">,</span><span style="color:#800080">$raw</span><span style="color:#000000">,</span><span style="color:#800080">$raw</span><span style="color:#000000">.</span><span style="color:#8b4513">length</span><span style="color:#000000">,</span><span style="color:#000000">0x8</span><span style="color:#000000">,[</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbStructInfo</span><span style="color:#000000">)
    </span><span style="color:#800080">$pvStructInfo</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">System.Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">AllocHGlobal</span><span style="color:#000000">(</span><span style="color:#800080">$pcbStructInfo</span><span style="color:#000000">)
    [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">pki.crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptDecodeObject</span><span style="color:#000000">(</span><span style="color:#000000">65537</span><span style="color:#000000">,</span><span style="color:#000000">1</span><span style="color:#000000">,</span><span style="color:#800080">$raw</span><span style="color:#000000">,</span><span style="color:#800080">$raw</span><span style="color:#000000">.</span><span style="color:#8b4513">length</span><span style="color:#000000">,</span><span style="color:#000000">0x8</span><span style="color:#000000">,</span><span style="color:#800080">$pvStructInfo</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbStructInfo</span><span style="color:#000000">)
    </span><span style="color:#800080">$struct</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">System.Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">PtrToStructure</span><span style="color:#000000">(</span><span style="color:#800080">$pvStructInfo</span><span style="color:#000000">,[</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">+CERT_SIGNED_CONTENT_INFO])
    </span><span style="color:#800080">$tbsData</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> byte[] </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> </span><span style="color:#800080">$struct</span><span style="color:#000000">.</span><span style="color:#8b4513">ToBeSigned</span><span style="color:#000000">.</span><span style="color:#8b4513">cbData</span><span style="color:#000000">
    [</span><span style="color:#008080">System.Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">Copy</span><span style="color:#000000">(</span><span style="color:#800080">$struct</span><span style="color:#000000">.</span><span style="color:#8b4513">ToBeSigned</span><span style="color:#000000">.</span><span style="color:#8b4513">pbData</span><span style="color:#000000">,</span><span style="color:#800080">$tbsData</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#800080">$tbsData</span><span style="color:#000000">.</span><span style="color:#8b4513">Length</span><span style="color:#000000">)
    </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> byte[] </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> </span><span style="color:#800080">$struct</span><span style="color:#000000">.</span><span style="color:#8b4513">Signature</span><span style="color:#000000">.</span><span style="color:#8b4513">cbData</span><span style="color:#000000">
    [</span><span style="color:#008080">System.Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">Copy</span><span style="color:#000000">(</span><span style="color:#800080">$struct</span><span style="color:#000000">.</span><span style="color:#8b4513">Signature</span><span style="color:#000000">.</span><span style="color:#8b4513">pbData</span><span style="color:#000000">,</span><span style="color:#800080">$signature</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#800080">$signature</span><span style="color:#000000">.</span><span style="color:#8b4513">Length</span><span style="color:#000000">)
    </span><span style="color:#800080">$algorithm</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> (</span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">System.Security.Cryptography.Oid</span><span style="color:#000000"> </span><span style="color:#800080">$struct</span><span style="color:#000000">.</span><span style="color:#8b4513">SignatureAlgorithm</span><span style="color:#000000">.</span><span style="color:#8b4513">pszObjId</span><span style="color:#000000">).FriendlyName
    </span><span style="color:#800080">$algorithm</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$algorithm</span><span style="color:#000000">.</span><span style="color:#8b4513">Replace</span><span style="color:#000000">(</span><span style="color:#800000">&quot;</span><span style="color:#800000">RSA</span><span style="color:#800000">&quot;</span><span style="color:#000000">,</span><span style="color:#000080">$null</span><span style="color:#000000">)
    </span><span style="color:#800080">$pubkey</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$issuer</span><span style="color:#000000">.</span><span style="color:#8b4513">PublicKey</span><span style="color:#000000">.</span><span style="color:#8b4513">Key</span><span style="color:#000000">
    </span><span style="color:#800080">$pubkey</span><span style="color:#000000">.</span><span style="color:#8b4513">VerifyData</span><span style="color:#000000">(</span><span style="color:#800080">$tbsData</span><span style="color:#000000">,</span><span style="color:#800080">$algorithm</span><span style="color:#000000">,</span><span style="color:#800080">$signature</span><span style="color:#000000">)
    [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">FreeHGlobal</span><span style="color:#000000">(</span><span style="color:#800080">$pvStructInfo</span><span style="color:#000000">)
}</span></pre></blockquote>
<p>And here is a little example:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] Test-CertificateSignature .\Desktop\digicert.cer .\Desktop\digicert_issuer.cer
True
<font color="#ff0000">[↓]</font> [vPodans] Test-CertificateSignature .\Desktop\digicert.cer .\Desktop\pica-1.cer
False
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>As you see, there is no magic, only the power of the Windows PowerShell!</p>
<p>Enjoy :)</p></div></div>
<div><b>Category:</b> PowerShell;CryptoAPI</div>
<div><b>Published:</b> 2012.04.06. 20:41</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PowerShell;CryptoAPI</category>
      <pubDate>Fri, 06 Apr 2012 17:41:36 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=66</guid>
    </item>
    <item>
      <title>Digging into digital signatures (part 1)</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=65</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass610DEEB120C14F899BC60453D4303DA9><p>Hi folks!</p> <p>A time ago I wrote a high-level description about the signatures in <a href="/Lists/Posts/Post.aspx?ID=27">Digital signatures</a> blog post. And today I want to demonstrate how this works in a real world.</p> <p>In a real world there are too many signature types, including RSA signatures (plain), Authenticode, XML, Document-specific (MS Word, Adobe PDF, etc.). The simplest signature type is plain RSA signatures. This type of signatures is widely used in PKI (certificates, CRLs, signed BLOBs and so on). In ASN.1 modules (as well as in unmanaged structures), signed BLOB is written like this:</p> <blockquote><pre>Certificate  ::=  SEQUENCE  {
        tbsCertificate       TBSCertificate,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }

AlgorithmIdentifier  ::=  SEQUENCE  {
        algorithm               OBJECT IDENTIFIER,
        parameters              ANY DEFINED BY algorithm OPTIONAL  }</pre></blockquote>
<p><strong>tbsCertificate</strong> contains an arbitrary data to be signed (look at the prefix, <strong>tbs</strong> means <strong>ToBeSigned</strong>). This data is always wrapped to a <strong>SEQUENCE</strong> (SEQUENCE models an ordered collection of variables of different type) which acts as a generic container in ASN.1. The next field is <strong>signatureAlgorithm</strong> of <strong>AlgorithmIdentifier</strong> complex type and <strong>signatureValue</strong> field of primitive <strong>BIT STRING</strong> type.</p>
<p><strong>AlgorithmIdentifier</strong> is exposed in next structure and contains 2 properties:</p>
<ul>
<li><strong>algorithm</strong> of primitive <strong>OBJECT IDENTIFIER</strong> type (encoded form of <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.oid.aspx">Oid</a> class). 
<li><strong>parameters</strong> of ANY. In most cases it is set to primitive type NULL.</li></ul>
<p>if you look into actual object you will see the following:</p>
<p><img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/65/image_68e0735d-dfa3-4cb8-8603-c86f0532c437_31B49BB8.png" width=755 height=389></p>
<p>Here we see:</p>
<ul>
<li><strong>tbsCertificate</strong> starts at offset 4 (first number in parentheses). In expanded view we see some data which represents certificate content (as you see in UI). 
<li><strong>signatureAlgorithm</strong> starts at offset 1408. 
<li><strong>algorithm</strong> starts at offset 1410. 
<li><strong>parameters</strong> starts at offset 1421 (NULL type). 
<li><strong>signatureValue</strong> starts at 1423 (BIT STRING).</li></ul>
<p>Here we have almost all required information to verify the signature. The only thing is missing — issuer certificate. Since issuer information is retrieved by using external means (through certificate chaining engine), it's certificate is not included in the certificate content. If issuer information is not retrieved by using external means, it is added explicitly. Such example is OCSP response:</p>
<p><img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/65/image_e1d30d3c-d9dd-4cdc-b905-21fcab91f060_31B49BB8.png" width=804 height=525></p>
<p>Generally signed content retains the same almost in all cases and CryptoAPI has appropriate structure <a href="http://msdn.microsoft.com/en-us/library/aa377540(VS.85).aspx">CERT_SIGNED_CONTENT_INFO</a>:</p>
<blockquote><pre>typedef struct _CERT_SIGNED_CONTENT_INFO {
  CRYPT_DER_BLOB             ToBeSigned;
  CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
  CRYPT_BIT_BLOB             Signature;
} CERT_SIGNED_CONTENT_INFO, *PCERT_SIGNED_CONTENT_INFO;</pre></blockquote>
<p>In .NET signature creation and verification stuff is implemented in <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx">RSACryptoServiceProvider</a> class. As we remember, signature is verified against issuer's public key. Let's do some manual PowerShell stuff:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] # get certificate objects.
<font color="#ff0000">[↓]</font> [vPodans] $digicert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 .\Desktop\digicert.c
er
<font color="#ff0000">[↓]</font> [vPodans] $issuer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 .\Desktop\digicert_iss
uer.cer
<font color="#ff0000">[↓]</font> [vPodans] # get tbsCertificate BLOB which starts at offset 4 and ends at 1407 (-1 to algorithmIdentifier)
<font color="#ff0000">[↓]</font> [vPodans] $tbsCertificate = $digicert.RawData[4..1407]
<font color="#ff0000">[↓]</font> [vPodans] $tbsCertificate.Length
1404
<font color="#ff0000">[↓]</font> [vPodans] # get signature value (minus tag byte and tag length bytes):
<font color="#ff0000">[↓]</font> [vPodans] $signatureValue = $digicert.RawData[1428..$digicert.RawData.Length]
<font color="#ff0000">[↓]</font> [vPodans] $signatureValue.Length
256
<font color="#ff0000">[↓]</font> [vPodans] # retrieve RSACryptoServiceProvider object of issuer' public key
<font color="#ff0000">[↓]</font> [vPodans] $pubkey = $issuer.PublicKey.Key
<font color="#ff0000">[↓]</font> [vPodans] $pubkey


PublicOnly           : True
CspKeyContainerInfo  : System.Security.Cryptography.CspKeyContainerInfo
KeySize              : 2048
KeyExchangeAlgorithm : RSA-PKCS1-KeyEx
SignatureAlgorithm   : http://www.w3.org/2000/09/xmldsig#rsa-sha1
PersistKeyInCsp      : False
LegalKeySizes        : {System.Security.Cryptography.KeySizes}



<font color="#ff0000">[↓]</font> [vPodans] $pubkey.GetType().FullName
System.Security.Cryptography.RSACryptoServiceProvider
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>We will use <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.verifydata.aspx">RSACryptoServiceProvider.VerifyData()</a> method to verify it:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $pubkey.VerifyData($tbsCertificate,&quot;sha1&quot;,$signatureValue)
True
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>And here we go! If we take different certificate (which is not an issuer of the subject's certificate):</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $issuer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 .\Desktop\pica-1.cer
<font color="#ff0000">[↓]</font> [vPodans] $pubkey = $issuer.PublicKey.Key
<font color="#ff0000">[↓]</font> [vPodans] $pubkey


PublicOnly           : True
CspKeyContainerInfo  : System.Security.Cryptography.CspKeyContainerInfo
KeySize              : 2048
KeyExchangeAlgorithm : RSA-PKCS1-KeyEx
SignatureAlgorithm   : http://www.w3.org/2000/09/xmldsig#rsa-sha1
PersistKeyInCsp      : False
LegalKeySizes        : {System.Security.Cryptography.KeySizes}



<font color="#ff0000">[↓]</font> [vPodans] $pubkey.VerifyData($tbsCertificate,&quot;sha1&quot;,$signatureValue)
False
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>And signature verification fails.</p>
<p>Though, this manual stuff is just an example. In the real world it is more efficient to deal with unmanaged structures, rather than each part manual parsing. Because you can take entire signed BLOB, convert it to unmanaged structure and marshal back to managed parts. I'll demonstrate unmanaged stuff in next post.</p></div></div>
<div><b>Category:</b> PKI;PowerShell</div>
<div><b>Published:</b> 2012.04.04. 22:28</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/65/image_68e0735d-dfa3-4cb8-8603-c86f0532c437_31B49BB8.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/65/image_68e0735d-dfa3-4cb8-8603-c86f0532c437_31B49BB8.png</a><br><a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/65/image_e1d30d3c-d9dd-4cdc-b905-21fcab91f060_31B49BB8.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/65/image_e1d30d3c-d9dd-4cdc-b905-21fcab91f060_31B49BB8.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell</category>
      <pubDate>Wed, 04 Apr 2012 19:28:29 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=65</guid>
    </item>
    <item>
      <title>Exploring enhanced features in X509CRL2 class</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=64</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass955C9289BFA146DFBDDD720284651F13><p>Hello S-1-1-0!</p> <p>Today I'll describe some interesting features implemented in X509CRL2 class. This class is available within my <a href="http://pspki.codeplex.com/">PowerShell PKI</a> module only (is not a part of .NET Framework).</p> <h3 align=center>Verify CRL signature</h3> <p>A time ago a came into an issue with CRL copy to remote web server.</p> <p>My internal CA publish CRLs to a local drive and custom script copies it to all required distribution points (internal and external web servers). And one day certificate validation failed due to <strong>Revocation Offline</strong> error. I've checked that CRL is correctly formed, is time valid and so on. But certificate chaining engine still reported mentioned error. Detailed investigation showed that unexpected network-level error occurred during file copy over internet and CRL signature become invalid. Since CRL object contains only signature value without signer certificate, normally it is impossible to verify whether the CRL signature is valid. In order to verify signature, you must obtain signer certificate (issuing CA certificate) and use custom steps to verify the signature.</p> <p>In order to simplify this process I've added a <strong>VerifySignature()</strong> method to an X509CRL2 class. Here is a little explanation, how it works:</p> <div style="width:935px"> <blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; ipmo pspki
PS C:\&gt; $crl = Get-CRL C:\CertData\pica-1.crl
PS C:\&gt; $crl


Version             : 2
Type                : Base CRL
IssuerDN            : System.Security.Cryptography.X509Certificates.X500DistinguishedName
Issuer              : CN=Sysadmins LV Internal Class 1 SubCA-1, OU=Information Systems, O=Sysadmins LV, C=LV
ThisUpdate          : 2012.03.31. 14:18:00
NextUpdate          : 2012.04.04. 14:38:00
SignatureAlgorithm  : System.Security.Cryptography.Oid
Extensions          : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography
                      .Oid, System.Security.Cryptography.Oid...}
RevokedCertificates : {Serial number: 40d897f4000000000109 revoked at: 2012.03.26. 21:17:00, Serial number: 497285fb000
                      000000105 revoked at: 2012.03.26. 18:21:00, Serial number: 1ad52cdc0000000000fb revoked at: 2012.
                      02.04. 22:32:00, Serial number: 222017d10000000000f1 revoked at: 2012.01.28. 11:25:15...}
RawData             : {48, 130, 4, 171...}
Handle              : 457143024</p></span></font></pre></blockquote></div>
<p>Here we see CRL object. Get the exposed public methods:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; $crl | gm -MemberType method


   TypeName: System.Security.Cryptography.X509Certificates.X509CRL2

Name             MemberType Definition
----             ---------- ----------
CertificateInCrl Method     bool CertificateInCrl(System.Security.Cryptography.X509Certificates.X509Certificate2 cert)
Encode           Method     string Encode(System.Security.Cryptography.X509Certificates.X509EncodingType encoding)
Equals           Method     bool Equals(System.Object obj)
Export           Method     System.Void Export(string path, System.Security.Cryptography.X509Certificates.X509Encodi...
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
Import           Method     System.Void Import(string path), System.Void Import(byte[] rawData)
Reset            Method     System.Void Reset()
ToString         Method     string ToString()
VerifySignature  Method     bool VerifySignature(System.Security.Cryptography.X509Certificates.X509Certificate2 issuer)


PS C:\&gt; $crl.VerifySignature.OverloadDefinitions
bool VerifySignature(System.Security.Cryptography.X509Certificates.X509Certificate2 issuer)</p></span></font></pre></blockquote></div>
<p>As we see, here is <strong>VerifySignature()</strong> method that accepts <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx">X509Certificate2</a> object (which represents possible issuer) and returns <strong>True</strong> (bool type) if signature is successfully decoded and verified by using issuer's public key. Otherwise false. Here are two examples:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; $crl.VerifySignature(&quot;C:\CertData\pica-1.crt&quot;)
True
PS C:\&gt; $crl.VerifySignature(&quot;C:\CertData\rca-1.crt&quot;)
False
PS C:\&gt;</p></span></font></pre></blockquote></div>
<h3 align=center>Determining whether the certificate is listed in CRL</h3>
<p>Another funny feature is to determine whether the particular certificate is revoked and it's reference is contained in the CRL's <strong>RevokedCertificates</strong> property. Ok, you can do this by processing this property over foreach loop and compare each entry's <strong>SerialNumber</strong> property with the presented certificate. However this method is not effective for large CRLs and may consume a lot of time. Fortunately, here is an unmanaged CryptoAPI function which do this task much faster: <a href="http://msdn.microsoft.com/en-us/library/aa376063(VS.85).aspx">CertFindCertificateInCRL</a>. And this function is used for <strong>CertificateInCrl()</strong> method of X509CRL2 class (see console view above). As a method parameter you pass X509Certificate2 object to verify. And how it works:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; $crl.CertificateInCrl(&quot;C:\CertData\revoked.cer&quot;)
True
PS C:\&gt; $cert = New-Object security.cryptography.x509certificates.x509certificate2 C:\CertData\revoked.cer
PS C:\&gt; $crl.RevokedCertificates | ?{$_.serialnumber -eq $cert.serialnumber}

SerialNumber                  RevocationDate                                   ReasonCode ReasonMessage
------------                  --------------                                   ---------- -------------
222017d10000000000f1          2012.01.28. 11:25:15                                      4 Superseded


PS C:\&gt;</p></span></font></pre></blockquote></div>
<p>In the first line I'm using native method to verify the certificate against CRL. In the rest lines I perform slow looping to show revoked certificate entry.</p>
<h3 align=center>Encoding CRLs</h3>
<p>Sometimes you may need to serialize CRL object so it can be transferred as a plain text and de-serialized by recipient. To address this issue I've added <strong>Encode()</strong> and <strong>Export()</strong> methods. <strong>Encode()</strong> method just encodes CRL to a Base64 (with or without headers) string and sends to caller (PowerShell console). <nobr><strong>Export()</strong></nobr> method exports CRL object to a file by using specified encoding type. The following encoding types are defined:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; [enum]::GetNames([System.Security.Cryptography.X509Certificates.X509EncodingType])
Base64
Base64Header
Binary
PS C:\&gt;</p></span></font></pre></blockquote></div>
<p><strong><font color="#ff0000">Note:</font></strong> <strong>Binary</strong> encoding type is not supported by <strong>Encode()</strong> method.</p>
<p>End here is encoding example:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; $crl.Encode(&quot;base64header&quot;)
-----BEGIN X509 CRL-----
MIIEqzCCA5MCAQEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UEBhMCTFYxFTATBgNVBAoTDFN5c2Fk
bWlucyBMVjEcMBoGA1UECxMTSW5mb3JtYXRpb24gU3lzdGVtczEuMCwGA1UEAxMlU3lzYWRtaW5z
IExWIEludGVybmFsIENsYXNzIDEgU3ViQ0EtMRcNMTIwMzMxMTExODAwWhcNMTIwNDA0MTEzODAw
WjCCAhMwKQIKQNiX9AAAAAABCRcNMTIwMzI2MTgxNzAwWjAMMAoGA1UdFQQDCgEFMCkCCklyhfsA
AAAAAQUXDTEyMDMyNjE1MjEwMFowDDAKBgNVHRUEAwoBBTAbAgoa1SzcAAAAAAD7Fw0xMjAyMDQy
MDMyMDBaMCkCCiIgF9EAAAAAAPEXDTEyMDEyODA5MjUxNVowDDAKBgNVHRUEAwoBBDApAgod0b+v
AAAAAADuFw0xMjAxMTkxNTMzMDBaMAwwCgYDVR0VBAMKAQUwKQIKYUd0bAAAAAAA1xcNMTEwOTI2
MjM1NzQ0WjAMMAoGA1UdFQQDCgEFMCkCCmFHbB8AAAAAANYXDTExMDkyNjIzNTc0NFowDDAKBgNV
HRUEAwoBBTApAgphR2Q/AAAAAADVFw0xMTA5MjYyMzU3NDRaMAwwCgYDVR0VBAMKAQUwKQIKEiJk
SAAAAAAAwBcNMTEwOTI2MTg1NzQxWjAMMAoGA1UdFQQDCgEFMCkCChIg0YIAAAAAALYXDTExMDky
NjE4NTc0MVowDDAKBgNVHRUEAwoBBTApAgphS+KzAAAAAADYFw0xMTA5MjYxODU2MzJaMAwwCgYD
VR0VBAMKAQUwKQIKYT+l4wAAAAAA1BcNMTEwOTI2MTg1NjMyWjAMMAoGA1UdFQQDCgEFMBsCCjv+
jncAAAAAAHgXDTEwMTIyNzE3MzIwMFqggdUwgdIwHwYDVR0jBBgwFoAUG/pecy1nE1zO0w7m6Hqp
YIwLY/wwEAYJKwYBBAGCNxUBBAMCAQAwCwYDVR0UBAQCAgWIMBwGCSsGAQQBgjcVBAQPFw0xMjA0
MDMxMTI4MDBaMDgGA1UdLgQxMC8wLaAroCmGJ2h0dHA6Ly93d3cuc3lzYWRtaW5zLmx2L3BraS9w
aWNhLTErLmNybDA4BgNVHRwBAf8ELjAsoCqgKIYmaHR0cDovL3d3dy5zeXNhZG1pbnMubHYvcGtp
L3BpY2EtMS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAGWjqNf0lDqt7LR4d9d3LaMf9E3XRvbPLwtG
UobBSuLe/Y/clQV0ZmzW8WdPuAapSDB1y0Q7bIAQSIQ90S3TXdY2zsB1Of96+LoepKDHdFQscRzj
FVLq6ZlamAHXQFDlqGHb3b8UcePrfARLG4/K2S1pHlBclEbzV8isARycks2D5fE58jW0azft9/u2
vsByYAf0/gNxDzOiF6iLSAydTnKSQvWAQ9XptGw5EpOaqj2ONds19v4nwMJDZwTnqxeW4U/OoTS3
TpwFWjaiGNtPoBdFlvAKZWtg+EIj7MtzhVdFzWfkq+6mRCNlhGEfP2aCGf+XaiO8rPMctgffkEgk
ivg=
-----END X509 CRL-----
PS C:\&gt;</p></span></font></pre></blockquote></div>
<p>Default X509CRL2 constructor (which accepts the path to a CRL file) and Import() method support CRL files with any of mentioned encoding types.</p>
<h3 align=center>Display CRL in UI</h3>
<p>What if you want to see the CRL in UI (like you double-clicked CRL file in Windows Explorer)? My module contains <a href="http://pspki.codeplex.com/wikipage?title=Show-CertificateRevocationList">Show-CertificateRevocationList</a> cmdlet. Previously the code was very dirty and you <font color="#ff0000">MUST NOT</font> use it:</p>
<blockquote><pre><span style="color:#800080">$tmpfile</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> ([</span><span style="color:#008080">IO.Path</span><span style="color:#000000">]::</span><span style="color:#8b4513">GetTempFileName</span><span style="color:#000000">()) </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">.crl</span><span style="color:#800000">&quot;</span><span style="color:#000000">
</span><span style="color:#5f9ea0;font-weight:bold">Set-Content</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Path</span><span style="color:#000000"> </span><span style="color:#800080">$tmpfile</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Value</span><span style="color:#000000"> </span><span style="color:#800080">$CRL</span><span style="color:#000000">.RawData </span><span style="font-style:italic;color:#5f9ea0">-Encoding</span><span style="color:#000000"> </span><span style="color:#800000">Byte</span><span style="color:#000000">
&amp; </span><span style="color:#800080">$tmpfile</span><span style="color:#000000">
</span><span style="color:#5f9ea0;font-weight:bold">Start-Sleep</span><span style="color:#000000"> </span><span style="color:#000000">2</span><span style="color:#000000">
</span><span style="color:#5f9ea0;font-weight:bold">Remove-Item</span><span style="color:#000000"> </span><span style="color:#800080">$tmpfile</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Force</span></pre></blockquote>
<p>The cmdlet just saved CRL to a temp file and removed upon completion. When I explored MSDN for some useful CryptoAPI functions (really, I like them) I found one good function: <a href="http://msdn.microsoft.com/en-us/library/aa380290(VS.85).aspx">CryptUIDlgViewContext</a>. This function displays certificate (this part is implemented in an <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2ui.aspx">X509Certificate2UI</a> class) CRL or CTL by using it's context handle. I just p/invoked this function and use it in <a href="http://pspki.codeplex.com/wikipage?title=Show-CertificateRevocationList">Show-CertificateRevocationList</a> cmdlet.</p></div></div>
<div><b>Category:</b> PKI;PowerShell</div>
<div><b>Published:</b> 2012.04.01. 14:12</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell</category>
      <pubDate>Sun, 01 Apr 2012 11:12:32 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=64</guid>
    </item>
    <item>
      <title>PS PKI v1.5 is released!</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=63</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass16D86720970743918764942CC5916A5E><p>I'm glad to announce that another build of my PowerShell PKI module is released! This release introduces new vision of the module evolution. Since now, it is not only a set of PowerShell commands, but the set of .NET APIs that can be used to extend existing commands. Let's go with details.</p> <h3 align=center>Breaking change</h3> <p>Due to the fact that Windows PKI team decided to name their own module in Windows Server 8 exactly as my module, I was forced to rename it. This is very disappointing thing. Now the module is named <strong>PSPKI</strong>. On the other side, PKI was too generic name and new name exposes usage area (PowerShell or simply PS).</p> <h3 align=center>Installation experience</h3> <p>Previously I've used a private signing certificate (issued by one of my internal CAs) to sign module files. Now I switched it to a certificate issued by common trusted CA (<a href="http://www.digicert.com/code-signing/">DigiCert</a>).</p> <p>During module packing, I've noticed very cool feature in <a href="http://www.advancedinstaller.com/">Advanced Installer</a>, that allows me to configure advanced product upgrade, so I can uninstall old PKI module and install new PSPKI one. So you can upgrade existing product with different name with new product name.</p> <h3 align=center>New commands</h3> <p>A time ago I promised to implement cmdlets that could be used to modify certificate template ACL. And here they are:</p> <ul> <li><a href="http://pspki.codeplex.com/wikipage?title=Get-CertificateTemplateAcl">Get-CertificateTemplateAcl</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Add-CertificateTemplateAcl">Add-CertificateTemplateAcl</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Remove-CertificateTemplateAcl">Remove-CertificateTemplateAcl</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Set-CertificateTemplateAcl">Set-CertificateTemplateAcl</a></li></ul> <p>The scheme is very similar to other. At first you retrieve certificate template object and pipe it to the <a href="http://pspki.codeplex.com/wikipage?title=Get-CertificateTemplateAcl">Get-CertificateTemplateAcl</a>, which extracts template ACL. Output object is a wrapper for <a href="http://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectorysecurity.aspx">ActiveDirectorySecurity</a> class:</p> <div style="width:935px"> <blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; Get-CertificateTemplate -Name webserver | Get-CertificateTemplateAcl

Path                                    Owner                                   Access
----                                    -----                                   ------
LDAP://CN=WebServer,CN=Certificate T... SYSADMINS\Enterprise Admins             {PKI.Security.AccessControlEntry, PK...


PS C:\&gt; (Get-CertificateTemplate -Name webserver | Get-CertificateTemplateAcl).access

IdentityReference                                                    AccessType Permissions
-----------------                                                    ---------- -----------
NT AUTHORITY\Authenticated Users                                          Allow {Read}
SYSADMINS\Domain Admins                                                   Allow {Read, Write, Enroll}
SYSADMINS\Enterprise Admins                                               Allow {Read, Write, Enroll}
SYSADMINS\Web Servers-G                                                   Allow {Read, Enroll}</p></span></font></pre></blockquote></div>
<p>I've decided to remove unnecessary fields to provide only most used fields and improve user experience with a little subset of permissions. You can easily compare this output with the native .NET output by running the commands:</p>
<blockquote>
<p><font size=2 face=Consolas>$template = Get-CertificateTemplate -Name webserver<br>([ADSI]$template.dn).ObjectSecurity.Access</font></p></blockquote>
<p>Once existing ACL is retrieved you can modify it by using either <a href="http://pspki.codeplex.com/wikipage?title=Add-CertificateTemplateAcl">Add-CertificateTemplateAcl</a>  or <a href="http://pspki.codeplex.com/wikipage?title=Remove-CertificateTemplateAcl">Remove-CertificateTemplateAcl</a> cmdlet. And finally, use <a href="http://pspki.codeplex.com/wikipage?title=Set-CertificateTemplateAcl">Set-CertificateTemplateAcl</a> to write modified ACL back to the original template object. I think, it is pretty easy.</p>
<p>Also I revisited <a href="/Lists/Posts/Post.aspx?ID=60">Test-WebServerSSL</a> script to integrate it with the module and added to the package.</p>
<h3 align=center>Code redesign</h3>
<p>While module covers only regular or common PKI tasks, I needed some non-standard features. For example, a year ago I wrote a PowerShell script that converts CRLs to a .NET like object (see: <a title="http://www.sysadmins.lv/PermaLink,guid,4ffce88a-e3f0-4dac-8e3f-4af7ba53f4f3.aspx" href="http://www.sysadmins.lv/PermaLink,guid,4ffce88a-e3f0-4dac-8e3f-4af7ba53f4f3.aspx">http://www.sysadmins.lv/PermaLink,guid,4ffce88a-e3f0-4dac-8e3f-4af7ba53f4f3.aspx</a>). While it works as expected, it can be very slow on big CRL (and several common CAs have large CRLs, 100kb+). Also it misses really useful methods. For example, you may need to verify whether the CRL was signed by the particular CA certificate. Or to know, whether the particular certificate is listed in CRL and so on.</p>
<p>It is almost impossible to solve all these tasks with regular PowerShell scripts, because it will require too many commands and it breaks code re-use, because large code blocks needs to be used in the various commands and PowerShell native performance is not so fast. I've decided to learn C# programming language and present common objects as a .NET classes and wrap them to PowerShell scripts as necessary. </p>
<p>At first, I moved all CryptoAPI (unmanaged) stuff to C# code. Mainly this includes CRL objects, CSPs. You can view. In addition I developed a set of generic classes and methods. You can use <strong>Add-Type</strong> cmdlet to view exposed classes:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] Add-Type -Path $PSHome\Modules\PSPKI\PKI.Core.dll -PassThru | sort name -Descending

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     X509EncodingType                         System.Enum
True     False    X509CRLEntryCollectionEnumerator         System.Object
True     False    X509CRLEntryCollection                   System.Object
True     False    X509CRLEntry                             System.Object
True     False    X509CRL2                                 System.Object
True     False    Wincrypt                                 System.Object
True     False    WebSSL                                   System.Object
True     True     TemplateRight                            System.Enum
False    False    SystemTime                               System.ValueType
True     False    Shift                                    System.Object
True     False    SecurityDescriptor                       System.Object
True     False    Schema                                   System.Object
True     False    RequestRow                               System.Object
False    False    PROV_ENUMALGS_EX                         System.ValueType
False    False    OSVersion                                System.Object
True     False    OCSPSingleResponseCollectionEnumerator   System.Object
True     False    OCSPSingleResponseCollection             System.Object
True     False    OCSPSingleResponse                       System.Object
True     True     OCSPResponseType                         System.Enum
True     True     OCSPResponseStatus                       System.Enum
True     True     OCSPResponseComplianceError              System.Enum
True     False    OCSPResponse                             System.Object
True     False    OCSPRequest                              System.Object
False    False    NCryptProviderName                       System.ValueType
False    False    NCryptAlgorithmName                      System.ValueType
True     False    nCrypt                                   System.Object
True     False    MessageSignature                         System.Object
True     False    KRAFlag                                  System.Object
True     False    KRA                                      System.Object
True     False    Kernel32                                 System.Object
True     False    InterfaceFlag                            System.Object
False    False    GenericArray                             System.Object
True     False    ExtensionList                            System.Object
True     False    Error                                    System.Object
True     False    EditFlag                                 System.Object
&lt;...&gt;</p></span></font></pre></blockquote></div>
<p><strong><font color="#ff0000">Note:</font></strong> library is compiled against .NET 2.0, so there are no additional requirements for module installation.</p>
<p>In next posts I'll talk about additional functionality that is available outside the PowerShell cmdlets/commands, but exist in the module package.</p>
<h5><font color="#ff0000">Extend your &lt;whatever you want&gt; with the power of Windows PowerShell!</font></h5>
<p align=center><a href="http://pspki.codeplex.com/"><font size=5><strong>Download PowerShell PKI Module v1.5 now!</strong></font></a></p></div></div>
<div><b>Category:</b> PKI;PowerShell</div>
<div><b>Published:</b> 2012.03.29. 22:26</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell</category>
      <pubDate>Thu, 29 Mar 2012 19:26:07 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=63</guid>
    </item>
    <item>
      <title>How to programmatically extract CDP, AIA and OCSP URLs from a digital certificate</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=62</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass817771ADB09944479A508F42D1226720><p>Hi folks! Today I want to demonstrate some useful stuff with CryptoAPI and PowerShell to extract CDP, AIA and OCSP URLs from a digital certificate.</p> <p>The start point for us is <a href="http://msdn.microsoft.com/en-us/library/aa380080(VS.85).aspx">CryptGetObjectUrl</a> function:</p> <blockquote><pre>BOOL WINAPI CryptGetObjectUrl(
  __in        LPCSTR pszUrlOid,
  __in        LPVOID pvPara,
  __in        DWORD dwFlags,
  __out       PCRYPT_URL_ARRAY pUrlArray,
  __inout     DWORD *pcbUrlArray,
  __out       PCRYPT_URL_INFO pUrlInfo,
  __inout     DWORD *pcbUrlInfo,
  __reserved  LPVOID pvReserved
);</pre></blockquote>
<p>as a <strong>pszUrlOid</strong> argument we will use the following constants: <strong>URL_OID_CERTIFICATE_ISSUER</strong> (from AIA extension) and <strong>URL_OID_CERTIFICATE_OCSP_AND_CRL_DIST_POINT</strong>. Constant values (as per Wincrypt.h) are:</p>
<ul>
<li>URL_OID_CERTIFICATE_ISSUER = 1; 
<li>URL_OID_CERTIFICATE_CRL_DIST_POINT = 2; 
<li>URL_OID_CERTIFICATE_ONLY_OCSP = 13.</li></ul>
<p><strong>pvPara</strong> accepth the handle to a certificate. <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx">X509Certificate2</a> object contains <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate.handle.aspx">Handle</a> property (which we will use).</p>
<p>In <strong>dwFlags</strong> we specify <strong>CRYPT_GET_URL_FROM_EXTENSION</strong> constant (0x2) to instruct the function to extract URLs from certificate extensions.</p>
<p><strong>pUrlArray</strong> will contains a byte array that represents little-endian Unicode strings. <strong>pcbUrlArray</strong> will contain a number of bytes to use for <strong>pUrlArray</strong> byte array. The rest arguments are not required for our task. Let's try to p/invoke this function in C# language:</p>
<blockquote><pre><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[DllImport(&quot;cryptnet.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptGetObjectUrl(
    int pszUrlOid,
    IntPtr pvPara,
    int dwFlags,
    byte[] pUrlArray,
    ref int pcbUrlArray,
    IntPtr pUrlInfo,
    ref int pcbUrlInfo,
    int pvReserved
);
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Cryptnet</span></pre></blockquote>
<p>Now, we need to define one helper function which will decode byte array to a little-endian Unicode string:</p>
<blockquote><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">ConvertTo-DERString</span><span style="color:#000000"> ([</span><span style="color:#008080">byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$bytes</span><span style="color:#000000">) {
    </span><span style="color:#800080">$SB</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">System.Text.StringBuilder</span><span style="color:#000000">
    </span><span style="color:#800080">$bytes1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$bytes</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{</span><span style="color:#800000">&quot;</span><span style="color:#800000">{0:X2}</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-f</span><span style="color:#000000"> </span><span style="color:#000080">$_</span><span style="color:#000000">}
    </span><span style="color:#0000ff">for</span><span style="color:#000000"> (</span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">; </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#800080">$bytes1</span><span style="color:#000000">.count; </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">2</span><span style="color:#000000">) {
        [</span><span style="color:#008080">void</span><span style="color:#000000">]</span><span style="color:#800080">$SB</span><span style="color:#000000">.Append([</span><span style="color:#008080">char</span><span style="color:#000000">](</span><span style="color:#5f9ea0;font-weight:bold">Invoke-Expression</span><span style="color:#000000"> 0x$((</span><span style="color:#800080">$bytes1</span><span style="color:#000000">[</span><span style="color:#800080">$n</span><span style="color:#ff0000">+</span><span style="color:#000000">1</span><span style="color:#000000">]) </span><span style="color:#ff0000">+</span><span style="color:#000000"> (</span><span style="color:#800080">$bytes1</span><span style="color:#000000">[</span><span style="color:#800080">$n</span><span style="color:#000000">]))))
    }
    </span><span style="color:#800080">$SB</span><span style="color:#000000">.ToString()
}</span></pre></blockquote>
<p>Before we starting CryptoAPI function usage, you need to note that the function MUST be called twice per operation: first time to determine resulting byte array length, and when the buffer is created, the second function call will write actual data to the buffer.</p>
<p>As an example, we will use the certificate from <a href="https://login.live.com">login.live.com</a>. If you are using Internet Explorer 7+ on Windows Vista+, it is not easy to copy the certificate from the web browser, because Internet Explorer Protected Mode prevents that. But don't worry, you can use my handy tool: <a href="/Lists/Posts/Post.aspx?ID=60">Test remote web server SSL certificate</a>. Just save Certificate.Handle property to a variable. Say:</p>
<blockquote><pre><span style="color:#800080">$pvPara</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> (</span><span style="color:#5f9ea0">Test-WebServerSSL</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-URL</span><span style="color:#000000"> </span><span style="color:#800000">login.live.com</span><span style="color:#000000">).Certificate</span></pre></blockquote>
<p>Ok, we now are ready to route:</p><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-CertificateURL</span><span style="color:#000000"> {
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [Parameter(Mandatory </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">)]
        [</span><span style="color:#008080">Security.Cryptography.X509Certificates.X509Certificate2</span><span style="color:#000000">]</span><span style="color:#800080">$Cert</span><span style="color:#000000">
    )
</span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[DllImport(&quot;cryptnet.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptGetObjectUrl(
    int pszUrlOid,
    IntPtr pvPara,
    int dwFlags,
    byte[] pUrlArray,
    ref int pcbUrlArray,
    IntPtr pUrlInfo,
    ref int pcbUrlInfo,
    int pvReserved
);
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Cryptnet</span><span style="color:#000000">
    </span><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">ConvertTo-DERString</span><span style="color:#000000"> ([</span><span style="color:#008080">byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$bytes</span><span style="color:#000000">) {
        </span><span style="color:#800080">$SB</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">System.Text.StringBuilder</span><span style="color:#000000">
        </span><span style="color:#800080">$bytes1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$bytes</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{</span><span style="color:#800000">&quot;</span><span style="color:#800000">{0:X2}</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-f</span><span style="color:#000000"> </span><span style="color:#000080">$_</span><span style="color:#000000">}
        </span><span style="color:#0000ff">for</span><span style="color:#000000"> (</span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">; </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#800080">$bytes1</span><span style="color:#000000">.count; </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">2</span><span style="color:#000000">) {
            [</span><span style="color:#008080">void</span><span style="color:#000000">]</span><span style="color:#800080">$SB</span><span style="color:#000000">.Append([</span><span style="color:#008080">char</span><span style="color:#000000">](</span><span style="color:#5f9ea0;font-weight:bold">Invoke-Expression</span><span style="color:#000000"> 0x$((</span><span style="color:#800080">$bytes1</span><span style="color:#000000">[</span><span style="color:#800080">$n</span><span style="color:#ff0000">+</span><span style="color:#000000">1</span><span style="color:#000000">]) </span><span style="color:#ff0000">+</span><span style="color:#000000"> (</span><span style="color:#800080">$bytes1</span><span style="color:#000000">[</span><span style="color:#800080">$n</span><span style="color:#000000">]))))
        }
        </span><span style="color:#800080">$SB</span><span style="color:#000000">.ToString()
    }
    </span><span style="color:#008000">#</span><span style="color:#008000"> create synthetic object to store resulting URLs</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#800080">$URLs</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">psobject</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Property</span><span style="color:#000000"> @{
        CDP </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">;
        AIA </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">;
        OCSP </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">;
    }
    </span><span style="color:#800080">$pvPara</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Cert</span><span style="color:#000000">.Handle
    </span><span style="color:#008000">#</span><span style="color:#008000"> process only if Handle is not zero.</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#ff0000">!</span><span style="color:#800080">$Cert</span><span style="color:#000000">.Handle.Equals([</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">)) {
        </span><span style="color:#008000">#</span><span style="color:#008000"> loop over each URL type: AIA, CDP and OCSP</span><span style="color:#008000">
</span><span style="color:#000000">        </span><span style="color:#0000ff">foreach</span><span style="color:#000000"> (</span><span style="color:#800080">$id</span><span style="color:#000000"> </span><span style="color:#0000ff">in</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">,</span><span style="color:#000000">2</span><span style="color:#000000">,</span><span style="color:#000000">13</span><span style="color:#000000">) {
            </span><span style="color:#008000">#</span><span style="color:#008000"> initialize reference variables</span><span style="color:#008000">
</span><span style="color:#000000">            </span><span style="color:#800080">$pcbUrlArray</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
            </span><span style="color:#800080">$pcbUrlInfo</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
            </span><span style="color:#008000">#</span><span style="color:#008000"> call CryptGetObjectUrl to get required buffer size. The function returns True if succeeds and False otherwise</span><span style="color:#008000">
</span><span style="color:#000000">            </span><span style="color:#0000ff">if</span><span style="color:#000000"> ([</span><span style="color:#008080">PKI.Cryptnet</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptGetObjectUrl</span><span style="color:#000000">(</span><span style="color:#800080">$id</span><span style="color:#000000">,</span><span style="color:#800080">$pvPara</span><span style="color:#000000">,</span><span style="color:#000000">2</span><span style="color:#000000">,</span><span style="color:#000080">$null</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbUrlArray</span><span style="color:#000000">,[</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbUrlInfo</span><span style="color:#000000">,</span><span style="color:#000080">$null</span><span style="color:#000000">)) {
                </span><span style="color:#008000">#</span><span style="color:#008000"> create buffers to receive the data</span><span style="color:#008000">
</span><span style="color:#000000">                </span><span style="color:#800080">$pUrlArray</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> byte[] </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> </span><span style="color:#800080">$pcbUrlArray</span><span style="color:#000000">
                </span><span style="color:#800080">$pUrlInfo</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">AllocHGlobal</span><span style="color:#000000">(</span><span style="color:#800080">$pcbUrlInfo</span><span style="color:#000000">)
                </span><span style="color:#008000">#</span><span style="color:#008000"> call CryptGetObjectUrl to receive decoded URLs to the buffer.</span><span style="color:#008000">
</span><span style="color:#000000">                [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.Cryptnet</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptGetObjectUrl</span><span style="color:#000000">(</span><span style="color:#800080">$id</span><span style="color:#000000">,</span><span style="color:#800080">$pvPara</span><span style="color:#000000">,</span><span style="color:#000000">2</span><span style="color:#000000">,</span><span style="color:#800080">$pUrlArray</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbUrlArray</span><span style="color:#000000">,</span><span style="color:#800080">$pUrlInfo</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbUrlInfo</span><span style="color:#000000">,</span><span style="color:#000080">$null</span><span style="color:#000000">)
                </span><span style="color:#008000">#</span><span style="color:#008000"> convert byte array to a single string</span><span style="color:#008000">
</span><span style="color:#000000">                </span><span style="color:#800080">$URL</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">ConvertTo-DERString</span><span style="color:#000000"> </span><span style="color:#800080">$pUrlArray</span><span style="color:#000000">
                </span><span style="color:#008000">#</span><span style="color:#008000"> parse unicode string to remove extra insertions</span><span style="color:#008000">
</span><span style="color:#000000">                </span><span style="color:#0000ff">switch</span><span style="color:#000000"> (</span><span style="color:#800080">$id</span><span style="color:#000000">) {
                    </span><span style="color:#000000">1</span><span style="color:#000000"> {
                        </span><span style="color:#800080">$URL</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$URL</span><span style="color:#000000">.Split(</span><span style="color:#800000">&quot;</span><span style="color:#800000">`0</span><span style="color:#800000">&quot;</span><span style="color:#000000">,[</span><span style="color:#008080">StringSplitOptions</span><span style="color:#000000">]::</span><span style="color:#8b4513">RemoveEmptyEntries</span><span style="color:#000000">)
                        </span><span style="color:#800080">$URLs</span><span style="color:#000000">.AIA </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$URL</span><span style="color:#000000">[4..(</span><span style="color:#800080">$URL</span><span style="color:#000000">.Length </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
                    }
                    </span><span style="color:#000000">2</span><span style="color:#000000"> {
                        </span><span style="color:#800080">$URL</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$URL</span><span style="color:#000000">.Split(</span><span style="color:#800000">&quot;</span><span style="color:#800000">`0</span><span style="color:#800000">&quot;</span><span style="color:#000000">,[</span><span style="color:#008080">StringSplitOptions</span><span style="color:#000000">]::</span><span style="color:#8b4513">RemoveEmptyEntries</span><span style="color:#000000">)
                        </span><span style="color:#800080">$URLs</span><span style="color:#000000">.CDP </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$URL</span><span style="color:#000000">[4..(</span><span style="color:#800080">$URL</span><span style="color:#000000">.Length </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
                    }
                    </span><span style="color:#000000">13</span><span style="color:#000000"> {
                        </span><span style="color:#800080">$URL</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$URL</span><span style="color:#000000"> </span><span style="color:#ff0000">-split</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">ocsp:</span><span style="color:#800000">&quot;</span><span style="color:#000000">
                        </span><span style="color:#800080">$URLs</span><span style="color:#000000">.OCSP </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$URL</span><span style="color:#000000">[1..(</span><span style="color:#800080">$URL</span><span style="color:#000000">.Length </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)] | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{</span><span style="color:#000080">$_</span><span style="color:#000000"> </span><span style="color:#ff0000">-replace</span><span style="color:#000000"> [</span><span style="color:#008080">char</span><span style="color:#000000">]</span><span style="color:#000000">0</span><span style="color:#000000">}
                    }
                }
                </span><span style="color:#008000">#</span><span style="color:#008000"> free unmanaged buffer</span><span style="color:#008000">
</span><span style="color:#000000">                [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">FreeHGlobal</span><span style="color:#000000">(</span><span style="color:#800080">$pUrlInfo</span><span style="color:#000000">)
            } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">No Urls</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
        }
        </span><span style="color:#800080">$URLs</span><span style="color:#000000">
    }
}</span></pre>
<p>And example:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] $cert = (Test-WebServerSSL login.live.com).Certificate
<font color="#ff0000">[↓]</font> [vPodans] Get-CertificateURL $cert | fl


AIA  : {http://EVSecure-aia.verisign.com/EVSecure2006.cer}
CDP  : {http://EVSecure-crl.verisign.com/EVSecure2006.crl}
OCSP : http://EVSecure-ocsp.verisign.com



<font color="#ff0000">[↓]</font> [vPodans] $cert = (Test-WebServerSSL www.startcom.org).Certificate
<font color="#ff0000">[↓]</font> [vPodans] Get-CertificateURL $cert | fl


AIA  : {http://www.startssl.com/certs/sub.class4.server.ca.crt}
CDP  : {http://www.startssl.com/crt4-crl.crl, http://crl.startssl.com/crt4-crl.crl}
OCSP : http://ocsp.startssl.com/sub/class4/server/ca



<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div></div></div>
<div><b>Category:</b> PKI;CryptoAPI;PowerShell</div>
<div><b>Published:</b> 2012.03.11. 13:59</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;CryptoAPI;PowerShell</category>
      <pubDate>Sun, 11 Mar 2012 11:59:07 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=62</guid>
    </item>
    <item>
      <title>Retrieve timestamp attribute from digital signature</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=61</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass10A1B3331A314826A03067FE46B0DDDC><p>One friend of mine asked about how to get signature creation time in PowerShell. When we sign a file, optionally (but recommended) we can timestamp the signature, thus approving that the file was signed at the certain moment and wasn't re-signed later. Some useful details about signatures and timestamps you can read in my previous article: <a href="/Lists/Posts/Post.aspx?ID=27">Digital signatures</a>.</p> <p>Here is what we see in the UI:</p> <p align=center><img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px" title="Digital Signature Details" border=0 alt="Digital Signature Details" src="/Lists/Posts/Attachments/61/image_a69baeaf-b927-43ff-9fcd-35e4cefbb7cc_58D9669A.png" width=423 height=493></p> <p>We see the following fields:</p> <ul> <li><strong>Name</strong> — name of the signer. This name is retrieved from the first CN attribute of the certificate subject.  <li><strong>E-mail</strong> — signer e-mail. E-mail address is retrieved from the E attribute of the certificate subject.  <li><strong>Signing time</strong> — this is the timestamp. The timestamp is digitally signed by the timestamp signing certificate (see the Countersignatures field).</li></ul> <p>Windows PowerShell has a built-in cmdlet to view and verify the signature: <a href="http://technet.microsoft.com/en-us/library/dd347607.aspx">Get-AuthenticodeSignature</a>. Let's see how it works:</p> <div style="width:935px"> <blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] Get-AuthenticodeSignature &quot;c:\Program Files (x86)\PowerGUI\ScriptEditor.exe&quot; | fl *


SignerCertificate      : [Subject]
                           E=support@quest.com, CN=Quest Software, O=Quest Software, C=US

                         [Issuer]
                           CN=GlobalSign ObjectSign CA, OU=ObjectSign CA, O=GlobalSign nv-sa, C=BE

                         [Serial Number]
                           0100000000011E46409D36

                         [Not Before]
                           17.12.2008 19:48:02

                         [Not After]
                           17.12.2011 19:48:02

                         [Thumbprint]
                           5C90629F628A3A5D64A4E300E28F3DEF19711EAC

TimeStamperCertificate : [Subject]
                           CN=VeriSign Time Stamping Services Signer - G2, O=&quot;VeriSign, Inc.&quot;, C=US

                         [Issuer]
                           CN=VeriSign Time Stamping Services CA, O=&quot;VeriSign, Inc.&quot;, C=US

                         [Serial Number]
                           3825D7FAF861AF9EF490E726B5D65AD5

                         [Not Before]
                           15.06.2007 3:00:00

                         [Not After]
                           15.06.2012 2:59:59

                         [Thumbprint]
                           ADA8AAA643FF7DC38DD40FA4C97AD559FF4846DE

Status                 : Valid
StatusMessage          : Signature verified.
Path                   : C:\Program Files (x86)\PowerGUI\ScriptEditor.exe



<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>The command displays signer certificate, status and timestamping certificates (countersignature certificate). However, it doesn't display the timestamp value. Unfortunately, there are no .NET classes, properties or methods to display it. When .NET lacks, CryptoAPI rulles! I wrote a simple wrapper for <a href="http://technet.microsoft.com/en-us/library/dd347607.aspx">Get-AuthenticodeSignature</a> cmdlet named Get-AuthenticodeSignatureEx:</p><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-AuthenticodeSignatureEx</span><span style="color:#000000"> {
</span><span style="color:#008000">&lt;#</span><span style="color:#008000">
.ForwardHelpTargetName Get-AuthenticodeSignature
</span><span style="color:#008000">#&gt;</span><span style="color:#000000">
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [Parameter(Mandatory </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">, ValueFromPipeline </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">, ValueFromPipelineByPropertyName </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">)]
        [</span><span style="color:#008080">String</span><span style="color:#000000">[]]</span><span style="color:#800080">$FilePath</span><span style="color:#000000">
    )
    </span><span style="color:#0000ff">begin</span><span style="color:#000000"> {
</span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[DllImport(&quot;crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptQueryObject(
    int dwObjectType,
    [MarshalAs(UnmanagedType.LPWStr)]string pvObject,
    int dwExpectedContentTypeFlags,
    int dwExpectedFormatTypeFlags,
    int dwFlags,
    ref int pdwMsgAndCertEncodingType,
    ref int pdwContentType,
    ref int pdwFormatType,
    ref IntPtr phCertStore,
    ref IntPtr phMsg,
    ref IntPtr ppvContext
);
[DllImport(&quot;crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptMsgGetParam(
    IntPtr hCryptMsg,
    int dwParamType,
    int dwIndex,
    byte[] pvData,
    ref int pcbData
);
[DllImport(&quot;crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptMsgClose(
    IntPtr hCryptMsg
);
[DllImport(&quot;crypt32.dll&quot;, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CertCloseStore(
    IntPtr hCertStore,
    int dwFlags
);
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-AssemblyName</span><span style="color:#000000"> </span><span style="color:#800000">System.Security</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Crypt32</span><span style="color:#000000">
    }
    </span><span style="color:#0000ff">process</span><span style="color:#000000"> {
        </span><span style="color:#5f9ea0;font-weight:bold">Get-AuthenticodeSignature</span><span style="color:#000000"> @PSBoundParameters | </span><span style="color:#5f9ea0;font-weight:bold">ForEach-Object</span><span style="color:#000000"> {
            </span><span style="color:#800080">$Output</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$_</span><span style="color:#000000">
            </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Output</span><span style="color:#000000">.SignerCertificate </span><span style="color:#ff0000">-ne</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">) {
                </span><span style="color:#800080">$pdwMsgAndCertEncodingType</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000">  </span><span style="color:#000000">0</span><span style="color:#000000">
                </span><span style="color:#800080">$pdwContentType</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000">  </span><span style="color:#000000">0</span><span style="color:#000000">
                </span><span style="color:#800080">$pdwFormatType</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000">  </span><span style="color:#000000">0</span><span style="color:#000000">
                [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$phCertStore</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
                [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$phMsg</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
                [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$ppvContext</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
                </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptQueryObject</span><span style="color:#000000">(
                    </span><span style="color:#000000">1</span><span style="color:#000000">,
                    </span><span style="color:#800080">$Output</span><span style="color:#000000">.Path,
                    </span><span style="color:#000000">16382</span><span style="color:#000000">,
                    </span><span style="color:#000000">14</span><span style="color:#000000">,
                    </span><span style="color:#000080">$null</span><span style="color:#000000">,
                    [</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pdwMsgAndCertEncodingType</span><span style="color:#000000">,
                    [</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pdwContentType</span><span style="color:#000000">,
                    [</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pdwFormatType</span><span style="color:#000000">,
                    [</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$phCertStore</span><span style="color:#000000">,
                    [</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$phMsg</span><span style="color:#000000">,
                    [</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$ppvContext</span><span style="color:#000000">
                )
                </span><span style="color:#800080">$pcbData</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
                </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptMsgGetParam</span><span style="color:#000000">(</span><span style="color:#800080">$phMsg</span><span style="color:#000000">,</span><span style="color:#000000">29</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#000080">$null</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbData</span><span style="color:#000000">)
                </span><span style="color:#800080">$pvData</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> byte[] </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> </span><span style="color:#800080">$pcbData</span><span style="color:#000000">
                </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptMsgGetParam</span><span style="color:#000000">(</span><span style="color:#800080">$phMsg</span><span style="color:#000000">,</span><span style="color:#000000">29</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#800080">$pvData</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pcbData</span><span style="color:#000000">)
                </span><span style="color:#800080">$SignedCms</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">Security.Cryptography.Pkcs.SignedCms</span><span style="color:#000000">
                </span><span style="color:#800080">$SignedCms</span><span style="color:#000000">.Decode(</span><span style="color:#800080">$pvData</span><span style="color:#000000">)
                </span><span style="color:#0000ff">foreach</span><span style="color:#000000"> (</span><span style="color:#800080">$Infos</span><span style="color:#000000"> </span><span style="color:#0000ff">in</span><span style="color:#000000"> </span><span style="color:#800080">$SignedCms</span><span style="color:#000000">.SignerInfos) {
                    </span><span style="color:#0000ff">foreach</span><span style="color:#000000"> (</span><span style="color:#800080">$CounterSignerInfos</span><span style="color:#000000"> </span><span style="color:#0000ff">in</span><span style="color:#000000"> </span><span style="color:#800080">$Infos</span><span style="color:#000000">.CounterSignerInfos) {
                        </span><span style="color:#800080">$sTime</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> (</span><span style="color:#800080">$CounterSignerInfos</span><span style="color:#000000">.SignedAttributes | ?{</span><span style="color:#000080">$_</span><span style="color:#000000">.Oid.Value </span><span style="color:#ff0000">-eq</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">1.2.840.113549.1.9.5</span><span style="color:#800000">&quot;</span><span style="color:#000000">}).Values | </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
                        </span><span style="color:#5f9ea0;font-weight:bold">Where-Object</span><span style="color:#000000"> {</span><span style="color:#000080">$_</span><span style="color:#000000">.SigningTime </span><span style="color:#ff0000">-ne</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">}
                    }
                }
                </span><span style="color:#800080">$Output</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">Add-Member</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberType</span><span style="color:#000000"> </span><span style="color:#800000">NoteProperty</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">SigningTime</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Value</span><span style="color:#000000"> </span><span style="color:#800080">$sTime</span><span style="color:#000000">.SigningTime.ToLocalTime() </span><span style="font-style:italic;color:#5f9ea0">-PassThru</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Force</span><span style="color:#000000">
                [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CryptMsgClose</span><span style="color:#000000">(</span><span style="color:#800080">$phMsg</span><span style="color:#000000">)
                [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.Crypt32</span><span style="color:#000000">]::</span><span style="color:#8b4513">CertCloseStore</span><span style="color:#000000">(</span><span style="color:#800080">$phCertStore</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)
            } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {
                </span><span style="color:#800080">$Output</span><span style="color:#000000">
            }
        }
    }
    </span><span style="color:#0000ff">end</span><span style="color:#000000"> {}
}</span></pre>
<p>The command usage is completely the same as for native <a href="http://technet.microsoft.com/en-us/library/dd347607.aspx">Get-AuthenticodeSignature</a> (if you run 'get-help Get-AuthenticodeSignatureEx' command, you will be redirected to original command help content). And the same example: </p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] Get-AuthenticodeSignatureEx &quot;c:\Program Files (x86)\PowerGUI\ScriptEditor.exe&quot; | fl *


<strong><font color="#ffffff">SigningTime            : 04.10.2011 17:06:35</font></strong>
SignerCertificate      : [Subject]
                           E=support@quest.com, CN=Quest Software, O=Quest Software, C=US

                         [Issuer]
                           CN=GlobalSign ObjectSign CA, OU=ObjectSign CA, O=GlobalSign nv-sa, C=BE

                         [Serial Number]
                           0100000000011E46409D36

                         [Not Before]
                           17.12.2008 19:48:02

                         [Not After]
                           17.12.2011 19:48:02

                         [Thumbprint]
                           5C90629F628A3A5D64A4E300E28F3DEF19711EAC

TimeStamperCertificate : [Subject]
                           CN=VeriSign Time Stamping Services Signer - G2, O=&quot;VeriSign, Inc.&quot;, C=US

                         [Issuer]
                           CN=VeriSign Time Stamping Services CA, O=&quot;VeriSign, Inc.&quot;, C=US

                         [Serial Number]
                           3825D7FAF861AF9EF490E726B5D65AD5

                         [Not Before]
                           15.06.2007 3:00:00

                         [Not After]
                           15.06.2012 2:59:59

                         [Thumbprint]
                           ADA8AAA643FF7DC38DD40FA4C97AD559FF4846DE

Status                 : Valid
StatusMessage          : Signature verified.
Path                   : C:\Program Files (x86)\PowerGUI\ScriptEditor.exe



<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>Look at the first property. Now you see a new property named <strong>SigningTime</strong> which contains desired value. And the rest properties still are there. At this time I can't tell, why the time in UI is GMT+2 (as my time zone), but .NET displays the time for GMT+3 (after adjusting the time to local time zone).</p>
<p>I've decided to add this code to my PowerShell PKI Module as an extended type system (ETS). This property will appear every time the <strong>System.Management.Automation.Signature</strong> object is created (without additional cmdlet).</p>
<p>HTH.</p></div></div>
<div><b>Category:</b> PowerShell;CryptoAPI;PKI</div>
<div><b>Published:</b> 2012.02.13. 20:07</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/61/image_a69baeaf-b927-43ff-9fcd-35e4cefbb7cc_58D9669A.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/61/image_a69baeaf-b927-43ff-9fcd-35e4cefbb7cc_58D9669A.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PowerShell;CryptoAPI;PKI</category>
      <pubDate>Mon, 13 Feb 2012 18:07:14 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=61</guid>
    </item>
    <item>
      <title>Test remote web server SSL certificate</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=60</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassB7053F3CC5984A71A5861DDD09290372><p>A time ago, Windows PKI team posted an article about a tool that allows you to check web server SSL certificate: <a href="http://blogs.technet.com/b/pki/archive/2011/02/22/verifying-the-ssl-certificate-expiration-with-a-tool.aspx">Verifying The SSL Certificate Expiration with a tool</a>. Unfortunately, the download link is broken. I have this tool and uploaded it to my weblog: <a title=VerifySSLCertificate href="/Tools/VerifySSLCertificate.zip">VerifySSLCertificate</a>.</p> <ul> <li>ZIP archive SHA1 hash: C633A3DC3E8A3AA6BDD714EABB925429076A160A  <li>Executable SHA1 hash: A13CE031F5C1331785E87B62D1464C6260549EC0</li></ul> <p>The tool is very good, but what if you want to run the test against a bulk of servers? Any sort of automation and batching means some PowerShell stuff :). To provide administrators with such tool I wrote a PowerShell script, where you can test web server SSL certificate and it's status. You can export required fields to XML or CSV for future examination/audit. Let's go:</p><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Test-WebServerSSL</span><span style="color:#000000"> {
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [Parameter(Mandatory </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">, ValueFromPipeline </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">, Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">)]
        [</span><span style="color:#008080">string</span><span style="color:#000000">]</span><span style="color:#800080">$URL</span><span style="color:#000000">,
        [Parameter(Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
        [ValidateRange(</span><span style="color:#000000">1</span><span style="color:#000000">,</span><span style="color:#000000">65535</span><span style="color:#000000">)]
        [</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$Port</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">443</span><span style="color:#000000">,
        [Parameter(Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">2</span><span style="color:#000000">)]
        [</span><span style="color:#008080">Net.WebProxy</span><span style="color:#000000">]</span><span style="color:#800080">$Proxy</span><span style="color:#000000">,
        [Parameter(Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">3</span><span style="color:#000000">)]
        [</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$Timeout</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">15000</span><span style="color:#000000">,
        [</span><span style="color:#008080">switch</span><span style="color:#000000">]</span><span style="color:#800080">$UseUserContext</span><span style="color:#000000">
    )
</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace PKI {
    namespace Web {
        public class WebSSL {
            public Uri OriginalURi;
            public Uri ReturnedURi;
            public X509Certificate2 Certificate;
            //public X500DistinguishedName Issuer;
            //public X500DistinguishedName Subject;
            public string Issuer;
            public string Subject;
            public string[] SubjectAlternativeNames;
            public bool CertificateIsValid;
            //public X509ChainStatus[] ErrorInformation;
            public string[] ErrorInformation;
            public HttpWebResponse Response;
        }
    }
}
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
    </span><span style="color:#800080">$ConnectString</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">https://$url`:$port</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$WebRequest</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Net.WebRequest</span><span style="color:#000000">]::</span><span style="color:#8b4513">Create</span><span style="color:#000000">(</span><span style="color:#800080">$ConnectString</span><span style="color:#000000">)
    </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">Proxy</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Proxy</span><span style="color:#000000">
    </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">Credentials</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">
    </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">Timeout</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Timeout</span><span style="color:#000000">
    </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">AllowAutoRedirect</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">
    [</span><span style="color:#008080">Net.ServicePointManager</span><span style="color:#000000">]::</span><span style="color:#8b4513">ServerCertificateValidationCallback</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> {</span><span style="color:#000080">$true</span><span style="color:#000000">}
    </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#800080">$Response</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">GetResponse</span><span style="color:#000000">()}
    </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {}
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">ServicePoint</span><span style="color:#000000">.</span><span style="color:#8b4513">Certificate</span><span style="color:#000000"> </span><span style="color:#ff0000">-ne</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">) {
        </span><span style="color:#800080">$Cert</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Security.Cryptography.X509Certificates.X509Certificate2</span><span style="color:#000000">]</span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">ServicePoint</span><span style="color:#000000">.</span><span style="color:#8b4513">Certificate</span><span style="color:#000000">.</span><span style="color:#8b4513">Handle</span><span style="color:#000000">
        </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#800080">$SAN</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> (</span><span style="color:#800080">$Cert</span><span style="color:#000000">.Extensions | </span><span style="color:#5f9ea0;font-weight:bold">Where-Object</span><span style="color:#000000"> {</span><span style="color:#000080">$_</span><span style="color:#000000">.Oid.Value </span><span style="color:#ff0000">-eq</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">2.5.29.17</span><span style="color:#800000">&quot;</span><span style="color:#000000">}).Format(</span><span style="color:#000000">0</span><span style="color:#000000">) </span><span style="color:#ff0000">-split</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">, </span><span style="color:#800000">&quot;</span><span style="color:#000000">}
        </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {</span><span style="color:#800080">$SAN</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">}
        </span><span style="color:#800080">$chain</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">Security.Cryptography.X509Certificates.X509Chain</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> (</span><span style="color:#ff0000">!</span><span style="color:#800080">$UseUserContext</span><span style="color:#000000">)
        [</span><span style="color:#008080">void</span><span style="color:#000000">]</span><span style="color:#800080">$chain</span><span style="color:#000000">.</span><span style="color:#8b4513">ChainPolicy</span><span style="color:#000000">.</span><span style="color:#8b4513">ApplicationPolicy</span><span style="color:#000000">.</span><span style="color:#8b4513">Add</span><span style="color:#000000">(</span><span style="color:#800000">&quot;</span><span style="color:#800000">1.3.6.1.5.5.7.3.1</span><span style="color:#800000">&quot;</span><span style="color:#000000">)
        </span><span style="color:#800080">$Status</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$chain</span><span style="color:#000000">.</span><span style="color:#8b4513">Build</span><span style="color:#000000">(</span><span style="color:#800080">$Cert</span><span style="color:#000000">)
        </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">PKI.Web.WebSSL</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Property</span><span style="color:#000000"> @{
            OriginalUri </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$ConnectString</span><span style="color:#000000">;
            ReturnedUri </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Response</span><span style="color:#000000">.ResponseUri;
            Certificate </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">ServicePoint</span><span style="color:#000000">.</span><span style="color:#8b4513">Certificate</span><span style="color:#000000">;
            Issuer </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">ServicePoint</span><span style="color:#000000">.</span><span style="color:#8b4513">Certificate</span><span style="color:#000000">.</span><span style="color:#8b4513">Issuer</span><span style="color:#000000">;
            Subject </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$WebRequest</span><span style="color:#000000">.</span><span style="color:#8b4513">ServicePoint</span><span style="color:#000000">.</span><span style="color:#8b4513">Certificate</span><span style="color:#000000">.</span><span style="color:#8b4513">Subject</span><span style="color:#000000">;
            SubjectAlternativeNames </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$SAN</span><span style="color:#000000">;
            CertificateIsValid </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Status</span><span style="color:#000000">;
            Response </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Response</span><span style="color:#000000">;
            ErrorInformation </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$chain</span><span style="color:#000000">.</span><span style="color:#8b4513">ChainStatus</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">ForEach-Object</span><span style="color:#000000"> {</span><span style="color:#000080">$_</span><span style="color:#000000">.Status}
        }
        </span><span style="color:#800080">$chain</span><span style="color:#000000">.</span><span style="color:#8b4513">Reset</span><span style="color:#000000">()
        [</span><span style="color:#008080">Net.ServicePointManager</span><span style="color:#000000">]::</span><span style="color:#8b4513">ServerCertificateValidationCallback</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$null</span><span style="color:#000000">
    } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Error</span><span style="color:#000000"> </span><span style="color:#000080">$Error</span><span style="color:#000000">[0]
    }
}</span></pre>
<p>The code connects to a server by using provided host name, instantiates a SSL connection, retrieves actual SSL certificate and tests, whether the certificate is valid (full tests are performed, including revocation checking). The following parameters can be used:</p>
<ul>
<li><strong>-URL</strong> — specifies the remote web server address. You must specify only host name, without any protocol prefixes. The correct host name is something like this: www.domain.com. This is the only mandatory parameter. All other parameters are optional. 
<li><strong>-Port</strong> — if remote web server is configured to use a custom port (default is 443), you can specify a port number to connect. 
<li><strong>-Proxy</strong> — use this parameter to specify a web proxy address if you wish to use proxy. 
<li>-Timeout — the default connection timeout is set to 15 seconds. You can override the value, by specifying another value. Timeout value must be set in milliseconds. Say, 1 second timeout will be 1000 milliseconds and 20 seconds — 20000 milliseconds. 
<li><strong>-UseUserContext</strong> — by default, the certificate must chain up to a trusted CA, which certificate is trusted by the computer (installed in Local Machine\Trusted Root CAs). If the root CA is trusted by only current user — a test will fail. You can use this switch to override the default behavior, so the test will succeed if a root CA is trusted only by current user.</li></ul>
<p>Here are some examples:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] Test-WebServerSSL signin.ebay.com


OriginalURi             : https://signin.ebay.com/
ReturnedURi             : https://signin.ebay.com/
Certificate             : [Subject]
                            CN=signin.ebay.com, OU=Site Operations, O=eBay Inc., STREET=2145 Hamilton Ave, L=San Jose,
                          S=California, PostalCode=95125, C=US, SERIALNUMBER=2871352, OID.2.5.4.15=Private Organization
                          , OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US

                          [Issuer]
                            CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com
                          /rpa (c)06, OU=VeriSign Trust Network, O=&quot;VeriSign, Inc.&quot;, C=US

                          [Serial Number]
                            3EA2CB6BAC5BDED626A5AEA6D914E30C

                          [Not Before]
                            19.01.2011 2:00:00

                          [Not After]
                            24.01.2013 1:59:59

                          [Thumbprint]
                            9DB60558622A1FA3EF5C0683671751CFDA8C7253

Issuer                  : CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/r
                          pa (c)06, OU=VeriSign Trust Network, O=&quot;VeriSign, Inc.&quot;, C=US
Subject                 : CN=signin.ebay.com, OU=Site Operations, O=eBay Inc., STREET=2145 Hamilton Ave, L=San Jose, S=
                          California, PostalCode=95125, C=US, SERIALNUMBER=2871352, OID.2.5.4.15=Private Organization,
                          OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US
SubjectAlternativeNames : {DNS Name=signin.ebay.com, DNS Name=signin.ebay.at, DNS Name=signin.ebay.be, DNS Name=signin.
                          ebay.ca...}
<strong><font color="#ffffff">CertificateIsValid      : True
ErrorInformation        :</font></strong>
Response                : System.Net.HttpWebResponse



<font color="#ff0000">[↓]</font> [vPodans] Test-WebServerSSL trust.beeline.ru


OriginalURi             : https://trust.beeline.ru/
ReturnedURi             : https://trust.beeline.ru/
Certificate             : [Subject]
                            CN=trust.beeline.ru, OU=DIT, O=Vimpelcom, L=Moscow, S=Moscow, C=RU

                          [Issuer]
                            CN=Vimpelcom ExternalCA, O=Vimpelcom, C=RU

                          [Serial Number]
                            40C9BF400000000341D9

                          [Not Before]
                            02.02.2012 8:32:51

                          [Not After]
                            02.02.2013 8:42:51

                          [Thumbprint]
                            58FEEEC8676F7E2D106DEA4235B22AFC09086AEB

Issuer                  : CN=Vimpelcom ExternalCA, O=Vimpelcom, C=RU
Subject                 : CN=trust.beeline.ru, OU=DIT, O=Vimpelcom, L=Moscow, S=Moscow, C=RU
SubjectAlternativeNames :
<strong><font color="#ffffff">CertificateIsValid      : False
ErrorInformation        : {PartialChain, RevocationStatusUnknown, OfflineRevocation}</font></strong>
Response                : System.Net.HttpWebResponse



<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>In the output you will see some important details: certificate subject, issuer and Subject Alternative Name (SAN) extension names. The most important fields are bolded: <strong>CertificateIsValid</strong> displays whether the certificate has passed or failed all certificate checks. If at least one test fails — detailed error information will be set to <strong>ErrorInformation</strong> property. In the current example, the second certificate failed revocation checking (revocation information is unavailable) and has partial chain (the chain is missing one or more CA certificate and they are not downloadable/reachable). If the server has expired certificate, you will see the following information in these two properties:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>CertificateIsValid      : False
ErrorInformation        : {NotTimeValid}</p></span></font></pre></blockquote></div>
<p>The tool will return all certificate errors (not throwing only the first). Hope, you find the script helpful.</p></div></div>
<div><b>Category:</b> PKI;PowerShell</div>
<div><b>Published:</b> 2012.02.12. 16:10</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell</category>
      <pubDate>Sun, 12 Feb 2012 14:10:44 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=60</guid>
    </item>
    <item>
      <title>Test, whether CA server is online and which interfaces are available</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=59</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassD47F6A119E9742C0878EB1959B0A66C4><p>Few days ago someone asked me how to programmatically test whether CA server is online, and which interfaces (both administration — ICertAdmin and/or enrollment — ICertRequest) are available.</p> <p>At first, I want to mention that you can use the following CMD commands:</p> <ul> <li>certutil –ping</li></ul> <p>Pings certificate management (ICertAdmin) and enrollment (ICertRequest) interfaces. Optionally you can ping remote CA interfaces: certutil –config CAHostName\CAName –ping </p> <p>What if you want to do this programmatically? Nice question! Looking to CryptoAPI reference you can find the following methods: <a href="http://msdn.microsoft.com/en-us/library/cc226685(PROT.13).aspx">ICertAdminD::Ping</a> and <a href="http://msdn.microsoft.com/en-us/library/cc249724(PROT.13).aspx">ICertRequestD::Ping</a> methods. However, local COM interfaces does not support these methods. Workarounds? PowerShell has workaround! Here is a simple code example, that tests CA and interface availability:</p> <blockquote><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Test-CAOnline</span><span style="color:#000000"> {
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [Parameter(Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">)]
        [</span><span style="color:#008080">string</span><span style="color:#000000">]</span><span style="color:#800080">$Config</span><span style="color:#000000">,
        [</span><span style="color:#008080">switch</span><span style="color:#000000">]</span><span style="color:#800080">$ShowUI</span><span style="color:#000000">
    )
</span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@&quot;
</span><span style="color:#800000">[DllImport(&quot;Certadm.dll&quot;, CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool CertSrvIsServerOnline(
    string pwszServerName,
    ref bool pfServerOnline
);
</span><span style="color:#800000">&quot;@</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">CryptoAPI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">CertAdm</span><span style="color:#000000">
    </span><span style="color:#800080">$CertConfig</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ComObject</span><span style="color:#000000"> </span><span style="color:#800000">CertificateAuthority.Config</span><span style="color:#000000">
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Config</span><span style="color:#000000"> </span><span style="color:#ff0000">-ne</span><span style="color:#000000"> </span><span style="color:#800000">&quot;&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-and</span><span style="color:#000000"> </span><span style="color:#ff0000">!</span><span style="color:#800080">$Config</span><span style="color:#000000">.Contains(</span><span style="color:#800000">&quot;</span><span style="color:#800000">\</span><span style="color:#800000">&quot;</span><span style="color:#000000">)) {
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Error</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Category</span><span style="color:#000000"> </span><span style="color:#800000">InvalidArgument</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ErrorId</span><span style="color:#000000"> </span><span style="color:#800000">InvalidArgumentException</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
        </span><span style="font-style:italic;color:#5f9ea0">-Message</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Config string must be passed in 'CAHostName\CAName' form.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#0000ff">break</span><span style="color:#000000">
    } </span><span style="color:#0000ff">elseif</span><span style="color:#000000"> (</span><span style="color:#800080">$Config</span><span style="color:#000000"> </span><span style="color:#ff0000">-eq</span><span style="color:#000000"> </span><span style="color:#800000">&quot;&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-and</span><span style="color:#000000"> </span><span style="color:#ff0000">!</span><span style="color:#800080">$ShowUI</span><span style="color:#000000">) {
        </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#800080">$Config</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$CertConfig</span><span style="color:#000000">.GetConfig(</span><span style="color:#000000">0x3</span><span style="color:#000000">)}
        </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {
            </span><span style="color:#5f9ea0;font-weight:bold">Write-Error</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Category</span><span style="color:#000000"> </span><span style="color:#800000">ObjectNotFound</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ErrorId</span><span style="color:#000000"> </span><span style="color:#800000">ObjectNotFoundElement</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
            </span><span style="font-style:italic;color:#5f9ea0">-Message</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Certificate Services are not installed on local computer.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
            </span><span style="color:#0000ff">break</span><span style="color:#000000">
        }
    } </span><span style="color:#0000ff">elseif</span><span style="color:#000000"> (</span><span style="color:#800080">$Config</span><span style="color:#000000"> </span><span style="color:#ff0000">-eq</span><span style="color:#000000"> </span><span style="color:#800000">&quot;&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-and</span><span style="color:#000000"> </span><span style="color:#800080">$ShowUI</span><span style="color:#000000">) {
        </span><span style="color:#800080">$Config</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$CertConfig</span><span style="color:#000000">.GetConfig(</span><span style="color:#000000">0x1</span><span style="color:#000000">)
    }
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Config</span><span style="color:#000000">) {
        [</span><span style="color:#008080">void</span><span style="color:#000000">](</span><span style="color:#800080">$Config</span><span style="color:#000000"> </span><span style="color:#ff0000">-match</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">(.+)\\(.+)</span><span style="color:#800000">&quot;</span><span style="color:#000000">)
        </span><span style="color:#800080">$Server</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$matches</span><span style="color:#000000">[1]
        </span><span style="color:#800080">$CAName</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$matches</span><span style="color:#000000">[2]
        </span><span style="color:#800080">$ServerStatus</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$false</span><span style="color:#000000">
        </span><span style="color:#800080">$hresult</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">CryptoAPI.CertAdm</span><span style="color:#000000">]::</span><span style="color:#8b4513">CertSrvIsServerOnline</span><span style="color:#000000">(</span><span style="color:#800080">$Server</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$ServerStatus</span><span style="color:#000000">)
        </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$ServerStatus</span><span style="color:#000000">) {
            </span><span style="color:#800080">$CertAdmin</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ComObject</span><span style="color:#000000"> </span><span style="color:#800000">CertificateAuthority.Admin</span><span style="color:#000000">
            </span><span style="color:#800080">$CertRequest</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ComObject</span><span style="color:#000000"> </span><span style="color:#800000">CertificateAuthority.Request</span><span style="color:#000000">
            </span><span style="color:#800080">$CA</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">psobject</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Property</span><span style="color:#000000"> @{
                Name </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$CAName</span><span style="color:#000000">;
                ICertAdmin </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">;
                ICertRequest </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">
            }
            </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#800080">$retn</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$CertAdmin</span><span style="color:#000000">.GetCAProperty(</span><span style="color:#800080">$Config</span><span style="color:#000000">,</span><span style="color:#000000">0x6</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#000000">4</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)}
            </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {</span><span style="color:#800080">$CA</span><span style="color:#000000">.</span><span style="color:#8b4513">ICertAdmin</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$false</span><span style="color:#000000">}
            </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#800080">$retn</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$CertRequest</span><span style="color:#000000">.GetCAProperty(</span><span style="color:#800080">$Config</span><span style="color:#000000">,</span><span style="color:#000000">0x6</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#000000">4</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)}
            </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {</span><span style="color:#800080">$CA</span><span style="color:#000000">.</span><span style="color:#8b4513">ICertRequest</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$false</span><span style="color:#000000">}
            </span><span style="color:#800080">$CA</span><span style="color:#000000">
        } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {
            </span><span style="color:#5f9ea0;font-weight:bold">Write-Error</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Category</span><span style="color:#000000"> </span><span style="color:#800000">ObjectNotFound</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ErrorId</span><span style="color:#000000"> </span><span style="color:#800000">ObjectNotFoundException</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
            </span><span style="font-style:italic;color:#5f9ea0">-Message</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Unable to find a Certification Authority server on '$Server'.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        }
    } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#0000ff">return</span><span style="color:#000000">}
}</span></pre></blockquote>
<p>This is more complicated, but more helpful example. If you want to test local CA (when CA server is installed on the same computer), or remote CA server. Remote server can be specified explicitly by using –Config parameter. Remote CA server must be passed in a 'CAHostName\CAName' form. Alternatively you can use <nobr>–ShowUI</nobr> parameter to select from Enterprise CA list. In that case you must omit –Config parameter. Here are some useful examples:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>[Administrator] Test-CAOnline

Name                                                               ICertRequest                              ICertAdmin
----                                                               ------------                              ----------
Contoso CA                                                                 True                                    True


[Administrator] Test-CAOnline -Config &quot;dc2\contoso-dc2-ca&quot;

Name                                                               ICertRequest                              ICertAdmin
----                                                               ------------                              ----------
contoso-dc2-ca                                                             True                                    True


[Administrator] Test-CAOnline -ShowUI

Name                                                               ICertRequest                              ICertAdmin
----                                                               ------------                              ----------
contoso-DC2-CA                                                             True                                    True


[Administrator]</p></span></font></pre></blockquote></div>
<p>If CA server is unavailable — an error will be thrown.</p>
<p>HTH.</p></div></div>
<div><b>Category:</b> PKI;PowerShell;CryptoAPI</div>
<div><b>Published:</b> 2012.01.28. 12:16</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell;CryptoAPI</category>
      <pubDate>Sat, 28 Jan 2012 10:16:01 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=59</guid>
    </item>
    <item>
      <title>PS PKI v1.0 is released!</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=58</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass8CA3A3A5C1CD493CA77A0F51EBC2A75B><p>Hello мир! Yesterdays I've published another version of my PowerShell PKI module — <a href="http://pspki.codeplex.com/releases/view/79921">v1.0</a>. Here are release notes:</p> <h3 align=center>Installation experience</h3> <p>I've spent much time on reviewing existing installation experience. My main goals were:</p> <ul> <li>Provide a single package for different platforms — x86 and x64.  <li>Support direct updates (without requiring to manually remove previous installation).  <li>Provide custom installation scenarios — for current user or for all users.</li></ul> <p>As you may be noticed, previously I've used <a href="http://www.advancedinstaller.com/">Advanced Installer</a> (thanks to PowerShell MVP <a href="http://blogs.microsoft.co.il/blogs/ScriptFanatic/">Shay Levy</a> who advised me this product) to wrap my package in MSI. Advanced Installer has intuitive, well-designed (attractive) and rich UI and this product is (possible) the best for beginners like me. However, free license is not enough for custom installation scenarios (like 32/64-bit mixed packages, direct upgrades, patching and so on). In order to accomplish these goals, I've contacted <strong>Caphyon Advanced Installer</strong> team for some support here. Advanced Installer support was very quick and kind, so I'm ready to provide new installation experience.</p> <p>Now you need only single package to install the module on either x86 or x64 platform and all future updates will automatically upgrade existing installation.</p> <p>Besides these technical questions, I was thinking about installation paths. Generally speaking, Windows PowerShell team do not recommend to install custom modules to the default location: <em>%windir%\System32\WindowsPowerShell\v1.0\Modules</em> due to the fact that the folder may be replaced by certain updates or upgrades. I'm still looking for the best solution here. Therefore I've changed module installation default path from System32 folder to <strong>My Documents</strong> folder. By default it is installed to <em>My Documents\WindowsPowerShell\Modules</em> folder (for current user only). Optionally you can switch to System32 folder by checking corresponding check-box in installation UI.</p> <p>Even though the default path is My Documents folder and do not require administrator permissions, I don't think that this is a good idea, when any user can install the module by using MSI/EXE. This means that <font color="#ff0000">local administrator permissions are required for all cases</font>!</p> <h3 align=center>What is changed in the code?</h3> <ul> <li><strong>CRL Distribution Points</strong> and <strong>Authority Information Access</strong> extension management</li></ul> <p>During module usage I've faced some bad things. For example, it was not possible to replace all CDP/AIA URLs. You was able to remove particular URLs, but not replace them all. To address this issue I've revisited and changed <strong>AuthorityInformationAccess</strong> and <strong>CRLDistributionPoint</strong> objects, so now you receive one object per CA. All URLs are placed in the URI property:</p> <div style="width:935px"> <blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; Get-CA int* | get-cdp

DisplayName                              URI
-----------                              ---
Sysadmins LV Internal Class 1 SubCA-1    {65:C:\Windows\system32\CertSrv\CertEnroll\%3%8%9.crl, 65:\\sysadmins.lv\Sh...</p></span></font></pre></blockquote></div>
<p>You can expand the URI property by piping the object to '<span style="color:#5f9ea0;font-weight:bold">Select</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Expand</span><span style="color:#000000"> </span><span style="color:#800000">URI</span>' command and you'll get detailed information about each URI:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; Get-CA int* | get-cdp | select -ExpandProperty uri


RegURI           : 65:C:\Windows\system32\CertSrv\CertEnroll\%3%8%9.crl
ConfigURI        : C:\Windows\system32\CertSrv\CertEnroll\.crl
Flags            : {1, 64}
CRLPublish       : True
DeltaCRLPublish  : True
AddToCertCDP     : False
AddToFreshestCRL : False
AddToCRLCDP      : False
IDP              : False
&lt;...&gt;</p></span></font></pre></blockquote></div>
<p>Now you can create oneliners that will replace all links like this:</p>
<blockquote>
<p><font color="#804000">Get-CA | Get-CDP | Remove-CDP –URI * | Add-CDP –URI &quot;link1&quot;,&quot;link2&quot;,&quot;link3&quot; | Set-CDP</font></p></blockquote>
<ul>
<li><a href="http://pspki.codeplex.com/wikipage?title=Get-CertificationAuthority">Get-CertificationAuthority</a></li></ul>
<p>Another good improvement is in <a href="http://pspki.codeplex.com/wikipage?title=Get-CertificationAuthority">Get-CertificationAuthority</a> command. At first I've added short Get-CA alias, because even PowerShell has tab-completion, I had to press Tab button many times to get the right command. Now the things are easier. In addition, I've encountered an issue with annoying delays during CA information retrieval in the case when one or more CAs are offline. Even if I explicitly specify the right CA name (which is online). I've changed the behavior to filter out unnecessary CA objects and they are returned immediately after object construction (say, you've specified particular CA or CAs server which is online and there are other stopped CAs).</p>
<ul>
<li>Service start/stop operations</li></ul>
<p>Many commands (especially Set-* and Restore-*) has <strong>–RestartCA</strong> switch parameter to restart CA service to immediately apply changes. Previously there was a fixed 2sec timeout between StopService and StartService function calls. This fixed timeout causes service start issues when the CA database is relatively large. Now, the behavior is changed to wait until CA service is completely stopped and then call for service start. There are 2 notes:</p>
<p><strong><font color="#ff0000">Note:</font></strong> After service is started, CA server may not be immediately available. This is because, CA server continues database checking and will not respond to client calls.</p>
<p><strong><font color="#ff0000">Warning:</font></strong> do not use <strong>–RestartCA</strong> switch parameter and <strong>Start/Stop/Restart-CertificationAuthority</strong> commands against clustered CAs. This is because, when you try to stop CertSvc service, cluster will treat this as a node failure and will move CA resource to second node and CA cluster may fail. Instead, all service stop/start operations MUST be performed by using cluster tools (cluadmin.msc or Cluster PowerShell module), so the cluster service is aware about your actions. In other words, you must take appropriate resource offline or bring it back online.</p>
<h3 align=center>New stuff</h3>
<p>Mainly I've spent attention to existing commands and only 2 new commands are added:</p>
<ul>
<li><a title=Install-CertificationAuthority href="http://pspki.codeplex.com/wikipage?title=Install-CertificationAuthority">Install-CertificationAuthority</a></li>
<li><a title=Uninstall-CertificationAuthority href="http://pspki.codeplex.com/wikipage?title=Uninstall-CertificationAuthority">Uninstall-CertificationAuthority</a></li></ul>
<p>If you are subscribed to my blog or read it on a regular basis, you may notice that this is the same stuff as posted here: <a href="/Lists/Posts/Post.aspx?ID=55">Install Certification Authority with PowerShell</a>. Enjoy CA installation from PowerShell console! :)</p>
<h3 align=center>Other stuff</h3>
<p>I've performed some additional tests and can say about:</p>
<ul>
<li>PowerShell 3.0 support — not supported!</li></ul>
<p>The module isn't working in Windows PowerShell 3.0 CTP1 and partially works in CTP2. The problem (still exist) with CTP2 is that it won't load format (PKI.Format.ps1xml) file. Other functionality seems ok, but without formatting. Will wait for next bits.</p>
<ul>
<li>Clustered CA support</li></ul>
<p>The module supports clustered CAs with the only limitation mentioned above (about CA server start and stop operations). Everything else works just fine and is supported.</p>
<p>Other notes and downloads are available here: <a title=Downloads href="http://pspki.codeplex.com/releases/view/79921">Downloads</a></p>
<p>p.s. do not hesitate to share your opinions and suggestions regarding the module. It is designed for you and you have some good ideas to implement — you are welcome.</p>
<p>p.p.s. after new version publishing I've noticed that the module was downloaded 1k times (since project launch):</p>
<p><img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/58/image_1604499b-2087-4a70-910e-fbedfe5fa1c5_40A1F229.png" width=266 height=88></p>

<p>:)</p></div></div>
<div><b>Category:</b> PKI;PowerShell</div>
<div><b>Published:</b> 2012.01.05. 23:03</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/58/image_1604499b-2087-4a70-910e-fbedfe5fa1c5_40A1F229.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/58/image_1604499b-2087-4a70-910e-fbedfe5fa1c5_40A1F229.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell</category>
      <pubDate>Thu, 05 Jan 2012 21:03:06 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=58</guid>
    </item>
    <item>
      <title>Do I need to implement Online Responder for Root/Policy CAs?</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=57</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass77B747FE2ECE45FA9B831CDCFA0D8605><p>Hi S-1-1-0, PS Crypto Guy is again on the board! Today I want to discuss about implementing Online Responder for Root and Policy CAs.</p> <h3 align=center>Abstract</h3> <p><strong>Online Responder</strong> implements <strong>Online Certificate Status Protocol</strong> (<em>OCSP</em>) as a part of alternate certificate validation mechanism (or revocation provider). Classic PKI uses <strong>Certificate Revocation Lists</strong> (<em>CRL</em>) to provide an information about revoked and untrusted certificates issued by the particular <strong>Certification Authority</strong> (<em>CA</em>). Most applications perform certificate checking for revocation by downloading and examining the particular issuer's CRL (or CRLs). If the presented certificate's serial number is listed in the corresponding issuer's CRL, an application rejects that certificate. During the CA lifecycle, you sometimes revoke some unnecessary and untrusted certificates. For example, if a certificate holder lost his/her certificate and associated private key, or a user left the company. Each revoked certificate's serial number is added to the CRL.</p> <p>When you setup a new fresh CA server, an initial CRL is about 500 bytes in size. Each revoked certificate increases this size by about 30-80 bytes. If you revoke 1,000 certificates, a CRL size will increase by 30-80kb. In large environments this number of revoked certificates can be reached quite quickly. This cause network overload and certificate validation delays due to regular CRL transmission over the network and additional client resources (CPU) is used to decode large binary CRL.</p> <p>To address this issue, a OCSP was introduced. OCSP assumes client-server communications consuming fixed size — about 2kb regardless of CRL size. The CRL can be 1mb large (or even more), but OCSP communications still takes about 2kb for each certificate being validated. OCSP greatly reduce network load and certificate revocation delays.</p> <h3 align=center>Source of the problem</h3> <p>Since Windows Server 2008 implements Online Responder role, many administrators started Online Responder deployment within their private PKIs. In most cases, Online Responder is implemented for all CAs in the particular PKI, including Issuing, Policy (if any) and Root CAs. There is nothing wrong with such configuration, but it is really useless to implement Online Responder for offline CAs — Policy and Root. This is because, these CA roles issue certificates only to the subordinate CAs and not to other entities. While user and computer certificates are revoked quite frequently, it is unlikely to have many revoked CA certificates. Therefore Root and Policy CAs maintain an empty (or with only few revoked subordinate CA certificates) CRL.</p> <p>As said, a OCSP is intended to reduce large CRL retrieval and decode delays. Since empty CRL is about 500 bytes, there are no performance or any other benefits. Moreover, OCSP communication consumes more traffic, than empty CRL retrieval. Also, this causes additional administrative overhead in additional Online Responder configuration management.</p> <p>And remember, that OCSP is not a classic CRL replacement, just additional revocation provider and there are no strict requirements to implement OCSP for all CAs in the PKI. Ok, you can say, that some guys from VeriSign have implemented Online Responder for Root CAs too (while their CRLs are empty) — <a title="http://evsecure-crl.verisign.com/pca3-g5.crl" href="http://evsecure-crl.verisign.com/pca3-g5.crl">http://evsecure-crl.verisign.com/pca3-g5.crl</a>. I doubt that you are a large CA provider as VeriSign with active certificate support in worldwide.</p> <h3 align=center>Conclusion</h3> <p>By summarizing this post, we can conclude that Online Responder should be implemented for those CAs which have quite large CRLs or there is a tendency for CRL growing — most likely Issuing CAs, that issue certificates to end entities (users and computers). There are no benefits (at all) in implementing Online Responder for less active CAs that issue certificates only to other CAs. Therefore, you should not implement Online Responder for these CA roles unless there is a special requirement in the external certificate/security policy.</p></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.12.14. 21:30</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Wed, 14 Dec 2011 19:30:48 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=57</guid>
    </item>
    <item>
      <title>Database log files are not truncated when you perform a full Certification Authority database backup.</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=56</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass7A7CCA498D4046268D8CAE3CD5C6F92D><h5><strong>SYMPTOMS</strong></h5> <p>Consider the following scenario. You have Windows Server 2008 R2 with installed Active Directory Certification Authority role. When you perform a full database backup by using either certutil.exe utility, or Certification Authority, the database log files are not truncated, as expected and backup set may contain up to 60 database log files. When using certutil.exe tool, it reports that log files are successfully truncated:</p> <blockquote><pre>Backing up Database files: 100%
Backing up Log files: 100%
Truncating Logs: 100%
Backed up database to C:\Backup.
<font color="#ff0000">Database logs successfully truncated.</font>
CertUtil: -backupDB command completed successfully.</pre></blockquote>
<p>In the Application eventlog you can find a record with EventID = 225 and the following message:</p>
<blockquote><pre>certsrv.exe (2420) No log files can be truncated.</pre></blockquote>
<p>If you restart Certificate Services before database backup, all logs, except the newest (created after Certificate Services start), are successfully truncated.</p>
<p>In previous operating systems (Windows Server 2003 and Windows Server 2008), log files are truncated to the most recent log file after each successive backup.</p><strong>
<hr>

<h5>CAUSE</h5></strong>
<p>This behavior occurs due to internal changes in Certificate Services JET database to provide better stability in the case of unexpected Certificate Services exit.</p>
<p><strong><font color="#ff0000">Note:</font></strong> the following detailed description is provided for informative purposes only. The information below don't provide any steps to change the behavior.</p>
<p>After securing a backup of the database and log files, the log files can optionally be truncated. Log file volume increases with database activity, and truncating the log files will reduce the redundant records in the log files (thereby decreasing the disk space used to store the log files).<br> <br>The log files are provided for database integrity and efficiency. If a less-than-graceful exit occurs with the Certificate Services application, the next time Certificate Services is started, the database replays the log files to prevent data corruption from being introduced into the database.</p>
<p>Certificate Services database supports a number that is known as &quot;<strong>checkpoint</strong>&quot;. All log files behind this checkpoint number are protected from truncation. To determine the current checkpoint you can use <strong>esentutl.exe</strong> tool. The esentutl.exe tool is shipped with each Windows Server 2008 R2 installation and is stored in <strong>%windir%\System32</strong> folder. Here is an example syntax to use:</p>
<blockquote><pre>esentutl /mk &lt;PathToADatabaseFolder&gt;\edb.chk</pre></blockquote>
<p>and the following example output is returned:</p>
<blockquote><pre>Extensible Storage Engine Utilities for Microsoft(R) Windows(R)
Version 6.1
Copyright (C) Microsoft Corporation. All Rights Reserved.

Initiating FILE DUMP mode...
      Checkpoint file: .\CertLog\edb.chk

      LastFullBackupCheckpoint: (0x0,0,0)
      Checkpoint: (<strong><font color="#ff0000">0x3B</font></strong>,2E,70)
      FullBackup: (0x3B,8,16)
      FullBackup time: 11/26/2011 15:40:03</pre></blockquote>
<p>The number identifies the start log file number to protect. In a given example, the file is — edb0003B.log. Any log files behind this number (edb0003C.log, edb0003E.log, etc.) are protected from truncation. Certificate Services database maintains 60 latest log files created from the last Certificate Services start. When 61st (and subsequent) log file is created, a checkpoint is increased by one to keep only 60 latest log files.</p>
<p>As mentioned in this section, when Certificate Services is successfully started, the database replays the log files to prevent data corruption from being introduced into the database. In this case checkpoint number is feed to the current log file ID, thereby allowing to truncate all log files, created before Certificate Services start.</p>
<hr>

<h5>STATUS</h5>
<p>This behavior is by design. 
<hr>

<h5>WORKAROUND</h5>
<p>No workaround available. 
<hr>

<h5>APPLIES TO</h5>
<ul>
<li>Windows Server 2008 R2 RTM Standard, Enterprise and Datacenter editions 
<li>Windows Server 2008 R2 SP1 Standard, Enterprise and Datacenter editions 
<li>Active Directory Certificate Services</li></ul></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.11.30. 23:22</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Wed, 30 Nov 2011 21:22:49 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=56</guid>
    </item>
    <item>
      <title>Install Certification Authority with PowerShell</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=55</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass646D857716F24576A0743BA3B81D559A><p>Hi there! PowerShell Crypto Guy is again here!</p> <p>Today I've finished SetupCA.ps1 script testing and I'm ready to share it with you. Of course this is not the first attempt to install CA role from cmdline, there is already <a href="http://technet.microsoft.com/en-us/library/ee918754(WS.10).aspx">SetupCA.vbs</a> script written by Windows PKI team. To be honest, this is not the first PowerShell script for CA installation from cmdline. The first attempt was made by Hasain Alshakarti — <a title="http://secadmins.com/?dl_id=3" href="http://secadmins.com/?dl_id=3">http://secadmins.com/?dl_id=3</a>. However this script just illustrates basic API functionality with ability to specify CA name, CA certificate validity and CA type. There is no error handling at all, even whether the CA can be installed on the computer.</p> <p>My script is primarily intended for automated CA installation and as the only way to install CA service on Server Core installations, because there is no server manager UI. I will not post the script here, but attach as a file (there are 346 lines of PowerShell code).</p> <h3 align=center>Abstract</h3> <p>At first I want to compare my script — SetupCA.ps1 and Microsoft's SetupCA.vbs. The advantages of my script:</p> <ul> <li>Much less code (but who cares?);  <li>The code uses the most efficient APIs (unlike SetupCA.vbs that actively uses some hand-routines, instead of using available APIs); <li>Unlike original CASetup.vbs, PowerShell implementation can setup root CA with custom validity (by default 5 years); <li>User-friendly and unified syntax. Most parameters are self-explanatory;  <li>The script has improved error handling with detailed (as possible) error messages;  <li>It works really faster than VBS;</li></ul> <p>The disadvantages:</p> <ul> <li>Requires PowerShell 2.0 (not installed by default on Windows Server 2008/2008 R2 Server Core installations);  <li>Is published after SetupCA.vbs and has no chances to become so popular as existing VBS script.</li></ul> <p>But in any way, for PS guys this might be preferred, because PS really rocks!</p> <h3 align=center>Script parameters</h3> <p>The script shares 3 parametersets for CA installation:</p> <ol> <li><strong><font color="#0000ff">NewKeySet</font></strong> — to generate new public/private key pair. All parameters within this parameter set are optional;  <li><strong><font color="#0000ff">PFXKeySet</font></strong> — this parameterset is commonly used for CA failover cluster installations. During setup you specify only path to a PFX file and password.  <li><font color="#0000ff"><strong>ExistingKeySet</strong></font> — is similar to previous. During installation you specify CA certificate thumbprint. CA certificate must be already installed in system certificate store.</li></ol> <h4 align=center>Install CA with new keys</h4> <p>The following parameters can be used:</p> <ul> <li><font color="#0000ff">CAName</font> (optional)</li></ul> <p>This parameter specifies custom CA certificate name/subject (what you see in the certificate display UI). If not passed, a '&lt;ComputerName&gt;-CA' form is used for workgroup CAs and '&lt;DomainName&gt;-&lt;ComputerName-CA&gt;' form is used for domain CAs. The parameter supports Unicode names.</p> <ul> <li><font color="#0000ff">CADNSuffix</font> (optional)</li></ul> <p>This parameter specifies DN suffix to specify some additional information. For example, company name, country, city, etc. DN suffix is empty for workgroup CAs and includes current domain distinguished name (for example, DC=domain,DC=com). The parameter accepts suffixes in a X500 form, for example: OU=Information Systems, O=Sysadmins LV, C=LV.</p> <ul> <li><font color="#0000ff">CAType</font> (optional)</li></ul> <p>Specifies CA type — Standalone Root, Standalone Subordinate, Enterprise Root, Enterprise Subordinate. If not passed, for non-domain environments or if you don't have Enterprise Admins rights, Standalone Root is used. If you have Enterprise Admins rights and your forest already has installed CAs, Enterprise Subordinate is used. If no Enterprise CAs installed in the forest, Enterprise Root is used.</p> <ul> <li><font color="#0000ff">ParentCA</font> (optional)</li></ul> <p>This parameter allows you to specify parent CA location only if you install Enterprise Subordinate CA. For other CA types, the parameter is ignored. Parent CA information must be passed in the following form: CAComputerName\CASanitizedName. Sanitized name is a sanitized form of CA name (subject). Mostly sanitized name is the same as CA name (unless you use Unicode and/or special characters, that are disallowed in X500). If the parameter is not specified, a certificate request will be generated on the root of system drive. I've decided to not implement this parameter for Standalone Subordinate CAs, because mostly they are installed in a workgroup environments and direct request submission to other CAs is likely unavailable (due of computer authentication complexity in non-domain environments). However, if you need it — contact me.</p> <ul> <li><font color="#0000ff">CSP</font> (optional)</li></ul> <p>Specifies custom cryptographic service provider. By default 'RSA#Microsoft Software Key Storage Provider' is used (in most cases you will use default CSP). You need to explicitly specify custom CSP only when you setup completely CNG authority (CSPs with ECDSA prefix) or you use HSM. Each HSM uses it's own custom CSP. You must install HSM middleware before CA installation.</p> <p>The full list of supportable and available &quot;by default&quot; CSP for Windows Server 2008+ is:</p> <blockquote><pre>Microsoft Base Cryptographic Provider v1.0<br>Microsoft Base DSS Cryptographic Provider<br>Microsoft Base Smart Card Crypto Provider<br>Microsoft Enhanced Cryptographic Provider v1.0<br>Microsoft Strong Cryptographic Provider<br>RSA#Microsoft Software Key Storage Provider<br>DSA#Microsoft Software Key Storage Provider<br>ECDSA_P256#Microsoft Software Key Storage Provider<br>ECDSA_P384#Microsoft Software Key Storage Provider<br>ECDSA_P521#Microsoft Software Key Storage Provider<br>RSA#Microsoft Smart Card Key Storage Provider<br>ECDSA_P256#Microsoft Smart Card Key Storage Provider<br>ECDSA_P384#Microsoft Smart Card Key Storage Provider<br>ECDSA_P521#Microsoft Smart Card Key Storage Provider</pre></blockquote>
<ul>
<li><font color="#0000ff">KeyLength</font> (optional)</li></ul>
<p>This parameter specifies key length. If not specified, a 2048-bit key will be generated. There is a little trick: if you look to a CSP list (above), you will see that key length is specified for each ECDSA* provider. I've developed a script logic in that way, so the script ignores this parameter if one of ECDSA* CSP is explicitly chosen and uses key length that is supported by the CSP. Therefore you will not receive an error if you select 'ECDSA_P256#Microsoft Smart Card Key Storage Provider' CSP with 2048 key length. 256-bit key will be selected automatically.</p>
<ul>
<li><font color="#0000ff">HashAlgorithm</font> (optional)</li></ul>
<p>This parameter specifies hash algorithm that will be used for CA certificate/request hashing. Note that this is important for root CA installations. Subordinate CA certificates are hashed and signed by the parent CA with it's own settings. By default 'SHA1' is used (though this parameter is applicable for all CA installation types).</p>
<ul>
<li><font color="#0000ff">ValidForYears</font> (optional)</li></ul>
<p>Specifies the validity for root CA installations. By default root CA certificates are valid for 5 years. You can increase this value to 10, 20, 50, whatever you need. For any subordinate CA types this parameter is silently ignored. This is because subordinate CA validity is determined by the parent CA. This parameter accepts integer values, assuming that the value is specified in years.</p>
<ul>
<li><font color="#0000ff">RequestFileName</font> (optional)</li></ul>
<p>If you setup any sort of subordinate (not root) CAs you can specify custom path to a request file. By default request file is generated on the root of system drive.</p>
<h4 align=center>Install CA and specify PFX for input information</h4>
<p>As said, this setup type commonly is used when you setup additional failover cluster nodes or you restore CA from backup. If you specify PFX file, it is used as input information to properly setup Certification Authority. Therefore there are only 2 mandatory parameters:</p>
<ul>
<li><font color="#0000ff">CACertFile</font> (mandatory)</li></ul>
<p>Specifies the path to a PFX file with CA certificate. Relative paths are allowed. Setup API performs additional checks for the certificate. Therefore you must ensure if: this is CA certificate (but not EFS encryption ;)), CA certificate is trusted (for non-root certificates) and chains to trusted CA and CA certificate revocation checking can be performed. Otherwise you will unable to setup CA with that CA certificate.</p>
<ul>
<li><font color="#0000ff">Password</font> (mandatory)</li></ul>
<p>Specifies the password to open PFX file. The parameter supports only securestrings! You can't type a password as a simple text. This is made for security reasons. There are few ways to pass a password in a securestring form:</p>
<blockquote><pre><span style="color:#800080">$Password</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">Read-Host</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">–a</span></pre></blockquote>
<p>or</p>
<blockquote><pre><span style="color:#5f9ea0;font-weight:bold">ConvertTo-SecureString</span><span style="color:#000000"> &lt;plaintext&gt; </span><span style="font-style:italic;color:#5f9ea0">–a</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">–f</span></pre></blockquote>
<p>You can enclose last command in parentheses and pass directly as a parameter value.</p>
<h4 align=center>Install CA and specify already installed certificate</h4>
<p>This method differs with previous only by the place where the CA certificate is stored — in an external PFX file or already installed to the system store. Since it is already installed, the only parameter you need to specify is:</p>
<ul>
<li><font color="#0000ff">Thumbprint</font> (mandatory)</li></ul>
<p>this parameter specifies a thumbprint of the certificate to use. The certificate must be installed in Local Machine\Personal store and must be trusted (for non-root certificates) and must not be revoked (the issuer revocation information must be available).</p>
<h4 align=center>Common parameters</h4>
<p>The script uses some additional parameters that can be specified for any CA installation scenario:</p>
<ul>
<li><font color="#0000ff">DBDirectory</font> (optional)</li></ul>
<p>Specifies the path to a folder to store CA database. If not specified, the default path: %windir%\System32\CertLog folder is used. If you need to specify custom path (for example, shared storage for CA clusters), you need to specify the next parameter too. The path must be valid.</p>
<ul>
<li><font color="#0000ff">LogDirectory</font> (optional)</li></ul>
<p>Specifies the path to a folderto store CA database log files. By default %windir%\System32\CertLog folder is used. If you use custom path for either database or log folders, you must explicitly specify both paths. Probably I'll change this behavior in next versions.</p>
<ul>
<li><font color="#0000ff">OverwriteExisting</font> (optional)</li></ul>
<p>Specifies, whether to overwrite any existing database files in the specified directories.</p>
<ul>
<li><font color="#0000ff">AllowCSPInteraction</font> (optional)</li></ul>
<p>Specifies, whether the cryptographic service provider (CSP) is allowed to interact with the desktop. This parameter should be used only if you use custom hardware-based CSP (HSM or smart card CSP). In other cases you don't need to allow CSP interactions.</p>
<ul>
<li><font color="#0000ff">Force</font> (optional)</li></ul>
<p>By default, the script explicitly prompts you whether you want to install Certification Authority with selected values. If you want to implement silent (quiet) installations — specify this parameter to suppress any prompts during role installation.</p>
<h3 align=center>Script installation</h3>
<p>To install the script (expose included commands) you do either:</p>
<ul>
<li>copy file contents to a console. Not very good choice :) 
<li>dot-source the script.</li></ul>
<p>To dot-source the script you must type dot, space and path to a script file:</p>
<blockquote><pre><strong>.</strong> c:\temp\setupca.ps1</pre></blockquote>
<p>and all commands from the file will be exposed to the PowerShell session and can be used like other native commands.</p>
<h3 align=center>Examples</h3>
<p>To simplify script usage, I'll provide some common examples.</p>
<p>To install offline Root CA you can do something like this:</p>
<ul>
<li>Example 1</li></ul><pre><span style="color:#5f9ea0">Install-CertificationAuthority</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CAName</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">My Root CA</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CADNSuffix</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">OU=Information Systems, O=Sysadmins LV, C=LV</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-CAType</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Standalone Root</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ValidForYears</span><span style="color:#000000"> </span><span style="color:#000000">10</span></pre>
<p>In this scenario you setup new Standalone Root CA with &quot;CN=My Root CA, OU=Information Systems, O=Sysadmins LV, C=LV&quot; subject, that will be valid for 10 years. The CA will use default paths to CA database and log files and certificate will use 'RSA#Microsoft Software Key Storage Provider' CSP with 2048-bit key and SHA1 hashing algorithm.</p>
<ul>
<li>Example 2</li></ul><pre><span style="color:#5f9ea0">Install-CertificationAuthority</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CAName</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">My Root CA</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CADNSuffix</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">OU=Information Systems, O=Sysadmins LV, C=LV</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-CAType</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Standalone Root</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ValidForYears</span><span style="color:#000000"> </span><span style="color:#000000">20</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CSP</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">ECDSA_P256#Microsoft Smart Card Key Storage Provider</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-HashAlgorithm</span><span style="color:#000000"> </span><span style="color:#800000">SHA512</span></pre>
<p>This example is similar to previous, with the exception that this CA will be completely CNG/SHA2 root. CA certificate will use CNG (not RSA) keys and hashing algorithm will be SHA512.</p>
<ul>
<li>Example 3</li></ul><pre><span style="color:#5f9ea0">Install-CertificationAuthority</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CAName</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Clustered CA</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CADNSuffix</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">OU=Information Systems, O=Sysadmins LV, C=LV</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-CAType</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Enterprise Subordinate</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-KeyLength</span><span style="color:#000000"> </span><span style="color:#000000">4096</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-DBDirectory</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">S:\CertDB</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-LogDirectory</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">S:\CertLog</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-RequestFileName</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">S:\Clustered CA.req</span><span style="color:#800000">&quot;</span></pre>
<p>This example assumes that you setup CA cluster first node (but not necessary). CA database will be stored on a shared storage (attached with S: drive letter). CA certificate will use default 'RSA#Microsoft Software Key Storage Provider' with 4096-bit key and default SHA1 hashing algorithm. CA certificate validity will be determined by the parent CA. In addition, CA certificate request will be stored on the shared storage.</p>
<ul>
<li>Example 4</li></ul><pre><span style="color:#800080">$Password</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">Read-Host</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-AsSecureString</span><span style="color:#000000">
</span><span style="color:#5f9ea0">Install-CertificationAuthority</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CACertFile</span><span style="color:#000000"> .\</span><span style="color:#800000">ClusteredCA.pfx</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Password</span><span style="color:#000000"> </span><span style="color:#800080">$Password</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-DBDirectory</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">S:\CertDB</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-LogDirectory</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">S:\CertLog</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-OverwriteExisting</span></pre>
<p>This is two-line example. Say, you have successfully installed CA cluster first node and have exported CA certificate to a PFX, and moved it to the second node (to the current directory). At first you will be prompted for a password. Since you type password to a securestring prompt, no characters will be displayed. After that you will specify relative path to a PFX file and specify shared storage to store CA database and log files. You overwrite database files that was created during first node installation. Actually this command installs CA cluster second node.</p>
<ul>
<li>Example 5</li></ul><pre><span style="color:#5f9ea0">Install-CertificationAuthority</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CAName</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Company Enterprise CA-2</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-CADNSuffix</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">O=Company, E=companypky@company.com</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
</span><span style="font-style:italic;color:#5f9ea0">-CAType</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Enterprise Subordinate</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ParentCA</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">ca01.company.com\Company Enterprise CA-1</span><span style="color:#800000">&quot;</span></pre>
<p>From best-practices perspective this is not a very good example, because it assumes at least 2 tiers of Enterprise CAs. However, it is still common. In a given example, Enterprise Subordinate CA will be installed and certificate request will be sent directly to existing Enterprise CA — 'Company Enterprise CA-1' that is hosted on 'ca01.company.com'. Note that existing CA must be online and must issue 'Subordinate Certification Authority' template.</p>
<h3 align=center>Uninstall Certification Authority</h3>
<p>The script provides an ability to uninstall CA role from the server. CA removal command consist of two optional parameters (switches):</p>
<ul>
<li><font color="#0000ff">AutoRestart</font> (optional)</li></ul>
<p>Automatically restarts computer to complete CA role removal. Otherwise you will have to restart the server manually.</p>
<ul>
<li><font color="#0000ff">Force</font> (optional)</li></ul>
<p>By default, the commands prompts you whether you want to remove CA role. Use –Force switch to suppress all prompts.</p>
<p>The syntax is very simple:</p><pre><span style="color:#5f9ea0">Uninstall-CertificationAuthority</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-AutoRestart</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Force</span></pre>
<p>The command will uninstall CA role, suppresses all prompts and automatically restarts the server upon completion.</p>
<p>And the last use this button to download the script:</p>
<div>
<p style="border-bottom:silver 1px solid;position:relative;border-left:silver 1px solid;width:240px;height:66px;border-top:silver 1px solid;border-right:silver 1px solid"><span style="font-family:verdana,arial,sans-serif;cursor:pointer"><a style="border-bottom:0px;border-left:0px;width:240px;height:66px;border-top:0px;border-right:0px" href="/psscripts/SetupCA.ps1"><img style="border-bottom:0px;border-left:0px;width:240px;height:66px;border-top:0px;border-right:0px" alt="Download File" src="http://www.sysadmins.lv/images/buttons/transparent.gif"> </a><a style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px" href="/psscripts/SetupCA.ps1"><img style="border-bottom:0px;position:absolute;border-left:0px;border-top:0px;top:6px;border-right:0px;left:5px" alt="Download File" src="http://www.sysadmins.lv/images/buttons/pgui.png" width=48 height=45> </a><a style="text-decoration:none" href="/psscripts/SetupCA.ps1"><span style="position:absolute;width:167px;white-space:nowrap;color:#555555;overflow:hidden;top:7px;margin-right:5px;left:67px"><span style="display:block;visibility:hidden">1</span> <span style="line-height:1.25em;display:block;cursor:pointer;text-decoration:none;padding-top:1px" title="Download file">PS1 file <br>20,1 KB </span></span></a><a style="position:absolute;width:167px;white-space:nowrap;color:#0066a7;overflow:hidden;top:7px;margin-right:5px;text-decoration:none;left:67px" href="/psscripts/SetupCA.ps1">SetupCA.ps1</a> </span></p></div></div></div>
<div><b>Category:</b> PKI;PowerShell</div>
<div><b>Published:</b> 2011.11.22. 0:09</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell</category>
      <pubDate>Mon, 21 Nov 2011 22:09:09 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=55</guid>
    </item>
    <item>
      <title>PowerShell PKI module v0.9.2 release</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=54</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassAE899184D36F4EF5A6756C850CD8BEC5><p>Hi, S-1-1-0!</p> <p>Finally I have finished another PowerShell PKI module release. This is not a significant release, but is quite improved. During module usage (I'm using certutil.exe less an less) I found some bugs in the previous release. Now they are fixed (at least those that were reported). The most significant change is in a new functionality. There are 3 set of cmdlets to manage the following CA settings:</p> <h3 align=center>Interface settings</h3> <p>Enrollment (ICertRequest3) and management (ICertAdmin2) interface management consist of four cmdlets: </p> <ul> <li><a href="http://pspki.codeplex.com/wikipage?title=Get-InterfaceFlag">Get-InterfaceFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Enable-InterfaceFlag">Enable-InterfaceFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Disable-InterfaceFlag">Disable-InterfaceFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Restore-InterFaceFlagDefault">Restore-InterfaceFlagDefault</a></li></ul> <p>First cmdlet is used to retrieve existing interface settings. Enable/Disable-InterfaceFlag is used to enable or disable particular interface flag. Restore-InterfaceFlagDefault is used to restore default settings. This is useful if you have misconfigured interfaces and you cannot operate with your PKI in a normal way.</p> <h3 align=center>Key Recovery Agent (KRA) settings</h3> <p>KRA settings are used to configure CA behavior during key archival process. For example you can enable key archival for keys that were signed by 3rd party CA. By default, Windows CA denies archival request for those keys. Or you can prevent key verification during key archival. By default, Windows CA checks keys to be archived, whether they are suitable. CA just encrypts random data with one key (public or private) and tries to decrypt the data by using second key (private or public). This flag (SaveBadRequestKey) can be useful if incoming request uses custom CSP that is not installed on CA server. Everything depends on final tasks. KRA setting management consist of four cmdlets:</p> <ul> <li><a href="http://pspki.codeplex.com/wikipage?title=Get-KeyRecoveryAgentFlag">Get-KeyRecoveryAgentFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Enable-KeyRecoveryAgentFlag">Enable-KeyRecoveryAgentFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Disable-KeyRecoveryAgentFlag">Disable-KeyRecoveryAgentFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Restore-KeyRecoveryAgentFlagDefault">Restore-KeyRecoveryAgentFlagDefault</a></li></ul> <p>The meaning of these cmdlets is the same as for interface settings — retrieve, enable/disable and restore default flags. For quick-typing purposes, I've added short aliases to call these commands.</p> <h3 align=center>CRL settings</h3> <p>CRL settings determine CA server behavior during CRL publishing (when CA constructs new CRL) or certificate validation. There are a lot of settings, you can find them <a href="http://pspki.codeplex.com/wikipage?title=Disable-CertificateRevocationListFlag">here</a>. As previous settings, CRL setting management consist of four cmdlets:</p> <ul> <li><a href="http://pspki.codeplex.com/wikipage?title=Get-CertificateRevocationListFlag">Get-CertificateRevocationListFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Enable-CertificateRevocationListFlag">Enable-CertificateRevocationListFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Disable-CertificateRevocationListFlag">Disable-CertificateRevocationListFlag</a>  <li><a href="http://pspki.codeplex.com/wikipage?title=Restore-CertificateRevocationListFlagDefault">Restore-CertificateRevocationListFlagDefault</a></li></ul> <p>For quick-typing purposes, I've added short aliases to call these commands.</p> <h3 align=center>Other cmdlets</h3> <p>Also I've added several helper cmdlets:</p> <ul> <li><a href="http://pspki.codeplex.com/wikipage?title=Get-ErrorMessage">Get-ErrorMessage</a> — converts Win32 error codes do a human-readable text messages. Details are here: <a href="/Lists/Posts/Post.aspx?ID=52">Retrieve text messages for Win32 errors</a></li> <li><a href="http://pspki.codeplex.com/wikipage?title=Get-CryptographicServiceProviderCNG">Get-CryptographicServiceProviderCNG</a> — retrieves CNG crypto providers that implements key storage provider and CNG algorithms. Read this article for details: <a href="/Lists/Posts/Post.aspx?ID=47">Get registered CNG CSPs on the system</a></li> <li><a href="http://pspki.codeplex.com/wikipage?title=Show-CertificateRevocationList">Show-CertificateRevocationList</a> — just displays CRL object in a UI window.</li></ul> <h3 align=center>Future plans</h3> <p>In the future release I'm planning to add CA role installation (implies default CA installation UI wizard), extend *-ExtensionList cmdlet to include mandatory extensions to publish in issued certificates and certificate template ACL management. I would love to implement new functionality, but due of the lack of time, I can't. Therefore I can't tell you when you can expect next release, but I'll try till this year.</p> <h1 align=center><a href="http://pspki.codeplex.com/">&gt;&gt; PS PKI Module v0.9.2 &lt;&lt;</a></h1></div></div>
<div><b>Category:</b> PKI;PowerShell;CryptoAPI</div>
<div><b>Published:</b> 2011.11.16. 16:47</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;PowerShell;CryptoAPI</category>
      <pubDate>Wed, 16 Nov 2011 14:47:30 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=54</guid>
    </item>
    <item>
      <title>Web Enrollment pages fails after MS11-051 patch installation</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=53</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassE78447EDC5384EFFAD550E70F37FF93C><h5><strong>SYMPTOMS</strong></h5> <p>Consider the following scenario. You have Windows Server 2003 with installed Certification Authority and Web Enrollment components. When you try to access web enrollment pages from a Windows Vista-based (or newer) computer you receive a message box:</p> <blockquote> <p align=left><img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/53/image_2eb2dd5a-1ff1-4eb5-b342-b2443f4c4bd2_051E8C9B.png" width=584 height=261></p></blockquote> <blockquote> <p><font color="#804000">The certificate enrollment page you are attempting to access cannot be used with this version of Windows. To enable Web certificate enrollment for clients running Windows Vista, your administrator must update all Windows CA Web enrollment pages. To learn more about this issue and the steps needed to update Web enrollment pages to support all versions of Windows, see: </font> <p><a href="http://support.microsoft.com/kb/922706"><font color="#0000ff">http://support.microsoft.com/kb/922706</font></a></p></blockquote> <p>KB922706 page contains the following information:</p> <blockquote> <p><em>Security update MS11-051 replaces the fix in 922706 and we advise customers to install the security update 2518295 instead of this hotfix 922706.</em></p></blockquote> <p>After installing MS11-051 patch (<a href="http://support.microsoft.com/kb/2518295">KB2518295</a>) an error remains and you still cannot use web enrollment.</p><strong> <hr>  <h5>CAUSE</h5></strong> <p>The patch MS11-051 (published 13 June 2011) does not replace KB922706 for Windows Server 2003.</p> <p><strong><font color="#ff0000">Note:</font></strong> Windows Server 2008 and Windows Server 2008 R2 are not affected, because they already have KB922706.</p> <p> <hr> </p> <h5>RESOLUTION</h5> <p>Microsoft is working on MS11-051 patch update. See Workaround section how to work around the issue. <hr> </p> <h5>WORKAROUND</h5> <p>To work around this issue you must follow the steps described below: <ol> <li>Uninstall <strong>KB2518295</strong> from <strong>Add or Remove Programs</strong> applet.<br><strong>Note:</strong> by default security updates are not shown in Add or Remove Programs applet. Mark <strong>Show Updates</strong> check-box.</li> <li>Install KB922706 update. Use the links below to download appropriate update:<br><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=4758">Download link for Windows Server 2003 x86</a><br><a href="http://www.microsoft.com/download/en/details.aspx?amp;displaylang=en&amp;id=19063">Download link for Windows Server 2003 x64</a></li> <li>Install MS11-051 security patch. Use the links below to download appropriate update:<br><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=26328">Download link for Windows Server 2003 x86</a><br><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=26420">Download link for Windows Server 2003 x64</a></li></ol> <p>After update installation you may need to restart web site that serves enrollment web pages. To do that, do the following:</p> <ol> <li>In the <strong>Start –&gt; Administrative Tools</strong> select <strong>Internet Information Services (IIS) Manager</strong>.</li> <li>In the opened console, expand <strong>Computer Name\Web Sites</strong> node.</li> <li>Select <strong>Default Web Site</strong> entry.</li> <li>In the <strong>Actions</strong> menu, select <strong>Stop</strong> and then click <strong>Start</strong> from the <strong>Actions</strong> menu.</li></ol> <hr>  <h5>APPLIES TO</h5> <ul> <li>Windows Server 2003 (All service packs) x86 <li>Windows Server 2003 (All service packs) x64</li></ul></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.11.04. 19:21</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/53/image_2eb2dd5a-1ff1-4eb5-b342-b2443f4c4bd2_051E8C9B.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/53/image_2eb2dd5a-1ff1-4eb5-b342-b2443f4c4bd2_051E8C9B.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Fri, 04 Nov 2011 17:21:26 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=53</guid>
    </item>
    <item>
      <title>Retrieve text messages for Win32 errors</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=52</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassA287F03CB4A940CB8AC81829EA474309><p>Hi S-1-1-0! Today's topic is described in the post header :)</p> <p>I guess most of you have encountered with some application/system issues. Sometimes the only information you have is Win32 error code and nothing else. To find a text message for particular error you usually use Google/Bing and/or other tools, like Err.exe from Windows Server 2003 Resource Kit. Yesterday I wrote a PowerShell script that will convert Win32 error code to a readable text. The code uses <a href="http://msdn.microsoft.com/library/ms679351.aspx">FormatMessage()</a> WinAPI function. Here is a known limitation, this function doesn't handle network-related errors (that are defined in wininet.h header file). Hopefully my script resolves this limitation by adding a reference to the wininet.dll library when it is necessary. Here is a code snippet:</p><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ErrorMessage</span><span style="color:#000000"> {
[OutputType(</span><span style="color:#800000">'</span><span style="color:#800000">System.String</span><span style="color:#800000">'</span><span style="color:#000000">)]
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [Parameter(Mandatory </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">)]
        [</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$ErrorCode</span><span style="color:#000000">
    )
</span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@'
</span><span style="color:#800000">[DllImport(&quot;kernel32.dll&quot;, SetLastError=true)]
public static extern uint FormatMessage(
    uint dwFlags,
    IntPtr lpSource,
    int dwMessageId,
    uint dwLanguageId,
    ref IntPtr lpBuffer,
    uint nSize,
    IntPtr Arguments
);
[DllImport(&quot;kernel32.dll&quot;, SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr LoadLibrary(
    string lpFileName
);
[DllImport(&quot;kernel32.dll&quot;, SetLastError=true, CharSet=CharSet.Auto)]
public static extern bool FreeLibrary(
    IntPtr hModule
);
[DllImport(&quot;kernel32.dll&quot;, SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr LocalFree(
    IntPtr hMem
);
</span><span style="color:#800000">'@</span><span style="color:#000000">
    </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$signature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">Kernel32</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000">}
    </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#000080">$Error</span><span style="color:#000000">[0].Exception.Message; </span><span style="color:#0000ff">return</span><span style="color:#000000">}
    </span><span style="color:#800080">$StartBase</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">12000</span><span style="color:#000000">
    </span><span style="color:#800080">$EndBase</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">12176</span><span style="color:#000000">
    </span><span style="color:#800080">$ErrorHex</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">{0:x8}</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-f</span><span style="color:#000000"> </span><span style="color:#800080">$ErrorCode</span><span style="color:#000000">
    </span><span style="color:#800080">$HighBytes</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">iex</span><span style="color:#000000"> 0x$(</span><span style="color:#800080">$ErrorHex</span><span style="color:#000000">.Substring(</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#000000">4</span><span style="color:#000000">))
    </span><span style="color:#800080">$LowBytes</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">iex</span><span style="color:#000000"> 0x$(</span><span style="color:#800080">$ErrorHex</span><span style="color:#000000">.Substring(</span><span style="color:#000000">4</span><span style="color:#000000">,</span><span style="color:#000000">4</span><span style="color:#000000">))
    </span><span style="color:#800080">$lpMsgBuf</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$LowBytes</span><span style="color:#000000"> </span><span style="color:#ff0000">-gt</span><span style="color:#000000"> </span><span style="color:#800080">$StartBase</span><span style="color:#000000"> </span><span style="color:#ff0000">-and</span><span style="color:#000000"> </span><span style="color:#800080">$LowBytes</span><span style="color:#000000"> </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#800080">$EndBase</span><span style="color:#000000">) {
        </span><span style="color:#800080">$hModule</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.Kernel32</span><span style="color:#000000">]::</span><span style="color:#8b4513">LoadLibrary</span><span style="color:#000000">(</span><span style="color:#800000">&quot;</span><span style="color:#800000">wininet.dll</span><span style="color:#800000">&quot;</span><span style="color:#000000">)
        </span><span style="color:#800080">$dwChars</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.Kernel32</span><span style="color:#000000">]::</span><span style="color:#8b4513">FormatMessage</span><span style="color:#000000">(</span><span style="color:#000000">0xb00</span><span style="color:#000000">,</span><span style="color:#800080">$hModule</span><span style="color:#000000">,</span><span style="color:#800080">$LowBytes</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$lpMsgBuf</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,[</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">)
        [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.Kernel32</span><span style="color:#000000">]::</span><span style="color:#8b4513">FreeLibrary</span><span style="color:#000000">(</span><span style="color:#800080">$hModule</span><span style="color:#000000">)
    } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#800080">$dwChars</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.Kernel32</span><span style="color:#000000">]::</span><span style="color:#8b4513">FormatMessage</span><span style="color:#000000">(</span><span style="color:#000000">0x1300</span><span style="color:#000000">,[</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">,</span><span style="color:#800080">$ErrorCode</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$lpMsgBuf</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">,[</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">)}

    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$dwChars</span><span style="color:#000000"> </span><span style="color:#ff0000">-ne</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">) {
        ([</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">PtrToStringAnsi</span><span style="color:#000000">(</span><span style="color:#800080">$lpMsgBuf</span><span style="color:#000000">)).Trim()
        [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.Kernel32</span><span style="color:#000000">]::</span><span style="color:#8b4513">LocalFree</span><span style="color:#000000">(</span><span style="color:#800080">$lpMsgBuf</span><span style="color:#000000">)
    } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Error</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Category</span><span style="color:#000000"> </span><span style="color:#800000">ObjectNotFound</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
        </span><span style="font-style:italic;color:#5f9ea0">-ErrorId</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">ElementNotFoundException</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
        </span><span style="font-style:italic;color:#5f9ea0">-Message</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">No error messages are assoicated with error code: 0x$ErrorHex ($ErrorCode). Operation failed.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    }
}</span></pre>
<p>The usage is very simple:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] Get-ErrorMessage 0x80070005
Access is denied.
<font color="#ff0000">[↓]</font> [vPodans] # short notation of this error:
<font color="#ff0000">[↓]</font> [vPodans] Get-ErrorMessage 5
Access is denied.
<font color="#ff0000">[↓]</font> [vPodans] Get-ErrorMessage 0x80072ee6
The URL does not use a recognized protocol
<font color="#ff0000">[↓]</font> [vPodans] 0x80072ee6
-2147012890
<font color="#ff0000">[↓]</font> [vPodans] Get-ErrorMessage -2147012890
The URL does not use a recognized protocol
<font color="#ff0000">[↓]</font> [vPodans] Get-ErrorMessage 1
Incorrect function.
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>as you see, it accepts errors in 3 formats:</p>
<ul>
<li><strong>Hex string</strong>. This must be a hex string prepended by '<strong>0x</strong>' prefix.</li>
<li>Signed integer (either positive or negative, depending on actual value).</li>
<li><strong>Error code short (low bytes) part</strong>.</li></ul>
<p>Even though the script won't handle any Win32 errors, but, most of them — definitely and this function will be included as a part of my upcoming <a href="http://pspki.codeplex.com/">PowerShell PKI module</a> update.</p>
<p>HTH</p></div></div>
<div><b>Category:</b> CryptoAPI;PowerShell</div>
<div><b>Published:</b> 2011.09.27. 21:48</div>
]]></description>
      <author>Vadims Podans</author>
      <category>CryptoAPI;PowerShell</category>
      <pubDate>Tue, 27 Sep 2011 18:48:38 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=52</guid>
    </item>
    <item>
      <title>CA certificates and Untrusted Certificates container</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=51</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass3798A9F680FE45ADBAE7D752FC1519DA><p>As you may know a <a href="http://www.diginotar.com/">DigiNotar CAs</a> was compromised due of some reasons (<a href="http://googleonlinesecurity.blogspot.com/2011/08/update-on-attempted-man-in-middle.html">one</a>, <a href="http://www.nytimes.com/2011/08/31/technology/internet/hackers-impersonate-google-to-snoop-on-users-in-iran.html?_r=1">two</a>). Microsoft have decided to break DigiNotar CAs trust at all — <a title="http://support.microsoft.com/kb/2607712" href="http://support.microsoft.com/kb/2607712">http://support.microsoft.com/kb/2607712</a>. Trust breaking is performed as follows:</p> <ol> <li>DigiNotar CA certificates are removed from Windows Update; <li>DigiNotar CA certificates are removed from crypt32.dll on Windows Vista+; <li>DigiNotar CA certificates are moved from Trusted Root CAs container to Untrusted Certificates.</li></ol> <p>Who is the next? <a href="http://blogs.comodo.com/it-security/data-security/the-recent-ra-compromise/">Comodo</a>? However the discussion is not about DigiNotar and Comodo (obviously, yes?)</p> <p>One customer from TechNet forums asked, why mentioned <a href="http://support.microsoft.com/kb/2607712">update</a> updates crypt32.dll on Windows XP/Windows Server 2003? Really why? The short answer is here:  <a href="http://social.technet.microsoft.com/wiki/contents/articles/3147.aspx#Crypt32_dll_and_Microsoft_update">Certificate Chaining Engine (CCE)</a>. However I have noted that certificates in crypt32.dll are updated only on Windows Vista+ (and newer). Windows XP and Windows Server 2003 don't contains predefined certificates in crypt32.dll. Very interesting question. I have addressed this question to Windows PKI team and got an answer. The reason is that systems prior to Windows Vista can contain only end entity certificates in the Untrusted Certificates container. CA certificates are not handled by this container. This means that if you move a CA certificate to this container nothing happens. And this update (see above) changes Untrusted Certificates behavior to handle CA certificates in the store. This allows you to revoke even Root CA certificates by moving them from Trusted Root CAs container to Untrusted Certificates container. Or you can publish a CA certificate to Untrusted Certificates to explicitly break a trust to specified certificate. Even if it is already placed in the Trusted Root CAs container, because Untrusted Certificates has higher precedence over Trusted Root CAs. This behavior was already implemented in Windows Vista+ systems.</p> <p>Offtopic: do you want a EV certificate and <strike>green</strike>red bar in web browser? DigiNotar still sells EV certificates — <a title="http://www.diginotar.com/Products/ExtendedValidationSSL/tabid/622/Default.aspx" href="http://www.diginotar.com/Products/ExtendedValidationSSL/tabid/622/Default.aspx">http://www.diginotar.com/Products/ExtendedValidationSSL/tabid/622/Default.aspx</a> for €975 per 2 years :) don't miss a chance ;)</p></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.09.17. 22:42</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Sat, 17 Sep 2011 19:42:12 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=51</guid>
    </item>
    <item>
      <title>How to change CA certificate validity period</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=50</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass419D1129309F4233B272533DDDC4375C><p>Today I want to discuss one question about CA certificate validity and how this can be changed.</p> <h3 align=center>Issue background</h3> <p>A little abstract. When you install Windows Certification Authority the default value is 5 years. It is quite long period and many young administrators leave default value (especially if they are not very experienced in certificate services). After a time it appears that 5 years is too short validity for CA certificate and administrators lookups for a resolution.</p> <p>Another scenario, you have Enterprise Root CA and you want to deploy a new subordinate CA. Since Enterprise CAs uses certificate templates a default template (<strong>Subordinate Certification Authority</strong>) will be used. However this template contains default value for validity period — 5 years. Since 'Subordinate <strong>Certification Authority</strong>' template is version 1 it is not possible to change anything there except security permissions. Ok, you can duplicate default template and create new one for subordinate CAs. However this won't work because Enterprise Subordinate CA installation wizard hardcodes template information, as the result custom subordinate CA will not be used. Epic fail!</p> <p>However it is not so bad as it looks. The following information will help you to redefine CA certificate validity during initial installation and CA certificate renewal.</p> <h3 align=center>Root CA</h3> <p>Root CA certificate validity can be set only during AD CS role installation. It is not possible to change root CA certificate validity without certificate renewal. If your root CA certificate is valid for 5 years (default) and you want to increase this value you must create (or edit existing) <strong>CAPolicy.inf</strong> file and place it to system root folder (by default C:\Windows). <strong>CAPolicy.inf</strong> must contain at least this information:</p> <blockquote><pre><font color="#804000">[Version]
Signature = &quot;$Windows NT$&quot;

[certsrv_server]
RenewalValidityPeriodUnits = 10
RenewalValidityPeriod = years</font></pre></blockquote>
<p>The setting is self-explanatory. As it is shown the setting is used only during root CA certificate renewal. Even if you define this value in the <strong>CAPolicy.inf</strong> file before AD CS role installation you still need to specify initial CA certificate validity. Also many administrators use long keys (4096 bits and longer) for higher security. However long keys are not supported by all applications as the result it is necessary to reduce key length. To decrease key length you need to add this entry to <strong>[certsrv_server]</strong> section:</p>
<blockquote><pre><font color="#804000">RenewalKeyLength = 2048</font></pre></blockquote>
<p>Again, this setting will be used only during CA certificate renewal by using new key pair. Nowadays it is recommended to setup CAs with key length = 2048 bits for compatibility purposes. If you renew CA certificate and reuse existing keys this setting will be ignored. For more details you should read this article: <a href="http://technet.microsoft.com/en-us/library/cc728279(WS.10).aspx">CAPolicy.inf Syntax</a>. In fact you can redefine any values for CA certificates in the <strong>CAPolicy.inf</strong> with the following exceptions:</p>
<ul>
<li>CA certificate subject; 
<li>Cryptographis Service Provider (CSP) that is used for key generation.</li></ul>
<p>These settings can be changed only by reinstalling AD CS role.</p>
<h3 align=center>Subordinate CA</h3>
<p>Slightly different process occurs with non-root CAs — subordinate or intermediate. During subordinate CA installation you are not prompted for CA certificate validity. Also mentioned setting (renewal validity period) above takes no effect during CA certificate renewal. This is because subordinate CA certificate validity is determined by the issuer (Policy CA or Root CA). There is one general rule for issued certificate validity: <strong>issued certificate validity will be the least value of</strong>:</p>
<ul>
<li>estimated (remaining) CA certificate validity; 
<li><strong>ValidityPeriod</strong> and <strong>ValidityPeriodUnits</strong> setting in the CA configuration (see below); 
<li>value defined in the certificate template (if available).</li></ul>
<p>The following steps should be used to configure subordinate CA certificate depending on the issuer type.</p>
<h4 align=center>Issuer is Standalone CA</h4>
<p>If your Root/Policy CA is Standalone CA then subordinate CA certificate validity will be 1 year only (by default). To resolve this issue you must accordingly configure your root CA. The following commands will set the validity of all certificates issued by the CA:</p>
<blockquote><pre><font color="#804000">certutil -setreg CA\ValidityPeriodUnits 10
certutil -setreg CA\ValidityPeriod Years
net stop certsvc &amp;&amp; net start certsvc</font></pre></blockquote>
<p>consider to implement these lines in the CA post-installation script. Once this setting is applied, CA will issue certificates for 10 years. However it cannot exceed CA certificate remaining lifetime and can be less than defined above.</p>
<h4 align=center>Issuer is Enterprise CA</h4>
<p>While it is not recommended to deploy Enterprise CAs in two or more levels this configuration may exist. As stated above Enterprise CA always use template information to determine issued certificate validity. Default 'Subordinate Certification Authority' template define subordinate CA certificate validity to 5 years and is not enough for various PKI implementations. The only way to change subordinate CA validity is to duplicate existing version 1 template named '<strong>Subordinate Certification Authority</strong>' and create custom version 2 or 3 template with custom validity settings. Do not forget to add this template to Issuing Template list on issuer. In addition you need to set validity settings in the issuer configuration:</p>
<blockquote><pre><font color="#804000">certutil -setreg CA\ValidityPeriodUnits 10
certutil -setreg CA\ValidityPeriod Years
net stop certsvc &amp;&amp; net start certsvc</font></pre></blockquote>
<p>Since subordinate CA hardcodes default template name it is necessary to create (or edit existing) <strong>CAPolicy.inf</strong> on subordinate CA by adding the following line to <strong>[RequestAttributes]</strong> section:</p>
<blockquote><pre><font color="#804000">[Version]
Signature = &quot;$Windows NT$&quot;

[RequestAttributes]
CertificateTemplate = &quot;CustomTemplateCommonName&quot;</font></pre></blockquote>
<p>This setting will enforce CA server to use custom template information instead of default template. Now you can setup new Enterprise Subordinate CA and use custom template that defines extended validity for SubCA certificate.</p>
<p>For more details about CA certificate renewal read: <a href="/Lists/Posts/Post.aspx?ID=26">Root CA certificate renewal</a></p></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.09.11. 21:01</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Sun, 11 Sep 2011 18:01:11 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=50</guid>
    </item>
    <item>
      <title>How to remove expired user certificates from Active Directory</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=49</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassBBA658C86A494A43A41D1EDB0B37609E><p>Hi S-1-1-0! Today I would like to talk about one of the most requested case — expired user certificate removal from Active Directory.</p> <p>By default when user requests an authentication and/or encryption certificate from an Enterprise CA it is published to userCertificate property under user account in Active Directory. Published authentication certificate is used for certificate mapping to a user account (or group) and are used by domain controllers during certificate-based authentication. Encryption certificates can be used to provide an access to certain encrypted content. In the case of secure email, sender retrieves recipient's certificate from Active Directory and uses it for mail message encryption purposes. The same process occurs when a user want to provide an access to encrypted file (EFS) for another user. Retrieved certificate is used to re-encrypt symmetric encryption key material.</p> <p>The negative side here is that certificates sometime expires. If existing certificate is renewed it is added to the userCertificate attribute and expired certificates are not replaced. Certain applications can filter expired certificates and display/select only valid certificates. However other applications may not. In the large environments expired certificates increases Active Directory replication traffic. As the result certain companies performs sanity certificate cleanup on a regular basis. The question here — how can I do this? Lets explore some background and solutions.</p> <p><img style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px" title=image border=0 alt=image src="/Lists/Posts/Attachments/49/image_331b97f3-5fca-4c1e-a8ad-628cafe1c0df_74785B34.png" width=369 height=181></p> <p>This is how ADSIEdit.msc displays published certificates in userCertificate attribute. Actually they are stored as a DER encoded byte array. It seems that this format isn't user-friendly. Generally the process should be something like this:</p> <li>Retrieve user account from AD;  <li>Extract an array of byte arrays from userCertificate attribute;  <li>Instantiate a X509Certificate2 object by using <a href="http://msdn.microsoft.com/en-us/library/ms148413.aspx">X509Certificate2(Byte[])</a> constructor;  <li>Filter all invalid (expired, revoked, untrusted) certificates by using custom filters;  <li>Write back remaining certificates to the attribute.  <p>In any way good script will be quite complex. Fortunately we have <a href="http://www.quest.com/powershell/activeroles-server.aspx">Quest AD PKI Cmdlets</a>. These cmdlets contains several cmdlets to work with digital certificate:</p> <blockquote><pre><span style="color:#5f9ea0;font-weight:bold">Get-QADUser</span><span style="color:#000000"> </span><span style="color:#800000">username</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">Remove-QADCertificate</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Valid</span><span style="color:#000000">:</span><span style="color:#000080">$false</span></pre></blockquote>
<p>The first command retrieves invalid certificates (Valid = false). The second command removes these certificates from user account properties. Slightly modified script can be used for all users:</p>
<blockquote><pre><span style="color:#5f9ea0;font-weight:bold">Get-QADUser</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">Remove-QADCertificate</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Valid</span><span style="color:#000000">:</span><span style="color:#000080">$false</span></pre></blockquote>
<p>Pretty easy! As always I would advice to read my whitepaper at: <a href="http://www.quest.com/documents/landing.aspx?id=12189">Guide for Using Quest AD-PKI cmdlets</a></p>
<p>Have a fun with PowerShell and Quest cmdlets!</p>
</li></div></div>
<div><b>Category:</b> PowerShell;Quest PKI</div>
<div><b>Published:</b> 2011.08.23. 20:08</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/49/image_331b97f3-5fca-4c1e-a8ad-628cafe1c0df_74785B34.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/49/image_331b97f3-5fca-4c1e-a8ad-628cafe1c0df_74785B34.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PowerShell;Quest PKI</category>
      <pubDate>Tue, 23 Aug 2011 17:08:07 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=49</guid>
    </item>
    <item>
      <title>You cannot download CA certificate from web enrollment pages</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=48</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass9B6EDD2B898749189932FD06122C816F><h5><strong>SYMPTOMS</strong></h5> <p>When you try to download CA certificate from web enrollment pages you get a prompt message with unreadable proposed file name:</p> <blockquote> <p align=left><font color="#804000">Do you want to save certnew_cer?ReqID=CACert&amp;Renewal=1&amp;Enc=bin (1,09 KB) from<br>&lt;ServerName&gt;</font></p></blockquote> <p><a href="/Lists/Posts/Attachments/48/image_2_422286E1.png"><img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:block;float:none;margin-left:auto;border-top:0px;margin-right:auto;border-right:0px;padding-top:0px" title="Web enrollment pages" border=0 alt="Web enrollment pages" src="/Lists/Posts/Attachments/48/image_thumb_422286E1.png" width=240 height=172></a></p> <p>And when you press 'Save' button in the save file dialog nothing happens and file is not saved. You cannot close 'Save File' pop-up prompt even if you press 'Cancel' button.</p><strong> <hr>  <h5>CAUSE</h5></strong> <p>This issue occurs if you are using operating system listed in the '<strong>Applies to</strong>' section and <strong>Internet Explorer</strong> with enabled <strong>Enhanced Security Configuration (ESC)</strong>. Internet Explorer ESC applies strict security settings which prevent you from downloading CA certificate from web enrollment pages. For more information about IE ESC feature please read this article: <a href="http://technet.microsoft.com/en-us/library/dd883248(WS.10).aspx">Internet Explorer: Enhanced Security Configuration</a></p> <hr>  <h5>RESOLUTION</h5> <p>You need to disable Internet Explorer Enhanced Security Configuration.</p> <ol> <li>Logon to the server with local administrator permissions;  <li>Click <strong>Start</strong>, <strong>Administrative Tools</strong> and click <strong>Server Manager</strong>;  <li>On the right pane click '<strong>Configure IE ESC</strong>' link:<br><a href="/Lists/Posts/Attachments/48/untitled_2_422286E1.png"><img style="background-image:none;border-bottom:0px;border-left:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px" title="Configure IE ESC in Server Manager" border=0 alt="Configure IE ESC in Server Manager" src="/Lists/Posts/Attachments/48/untitled_thumb_422286E1.png" width=240 height=172></a>  <li>In the opened dialog box disable Internet Explorer ESC for appropriate group (Administrators and/or regular users).  <li>Click <strong>Ok</strong> and restart Internet Explorer.</li></ol> <p><strong><font color="#ff0000">Note:</font></strong> you should not disable Internet Explorer ESC for Administrators group. This is because by disabling this feature you increase the exposure of your server to potential attacks that can occur through Web content and application scripts. Instead you should access web enrollment pages by using regular user account and disable IE ESC for regular users only.</p> <hr>  <h5>WORKAROUND</h5> <p>In an Active Directory environment you should avoid web enrollment pages usage directly from servers. For management purposes you should use administrative computer that runs client operating system (Windows Vista/7) and with installed Remote Server Administration Tools (RSAT).  <hr>  <h5>APPLIES TO</h5> <ul> <li>Windows Server 2008 x86 and x64 all editions, full installation with Internet Explorer 8 or 9  <li>Windows Server 2008 R2 all editions, full installation with Internet Explorer 8 or 9</li></ul></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.08.17. 22:29</div>
<div><b>Attachments:</b> <a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/image_2_422286E1.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/image_2_422286E1.png</a><br><a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/image_thumb_422286E1.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/image_thumb_422286E1.png</a><br><a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/untitled_2_422286E1.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/untitled_2_422286E1.png</a><br><a href="http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/untitled_thumb_422286E1.png">http://en-us.sysadmins.lv/Lists/Posts/Attachments/48/untitled_thumb_422286E1.png</a><br><a href=""></a></div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Wed, 17 Aug 2011 19:29:50 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=48</guid>
    </item>
    <item>
      <title>Share management in PowerShell</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=28</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass2CFBA7665DC34E47B4B755FE9E9B8278><p>Surprise, it's me again! Today I have finished network share management module for PowerShell. I want to thank <a href="http://blogs.microsoft.co.il/blogs/ScriptFanatic/">Shay Levy</a> who helped me with module-related stuff. </p> <p>With this module you will be able to:</p> <ul> <li>List share (or shares) from local or from remote computers;  <li>Create new share with various settings;  <li>Remove share (actually this not remove folder itself, but stops sharing);  <li>Add/Set/Remove share permissions (note that share permissions and NTFS rights are not the same).</li></ul> <p>Here are module installation instructions:</p> <p>The ZIP file contains the module files only and you need to extract its content to one of two places:  <ol> <li>%USERPROFILE%\Documents\WindowsPowerShell\Modules  <li>%WINDIR%\System32\WindowsPowerShell\v1.0\Modules (need admin privileges)  <li><b>If the directory tree (of one of the above) doesn't exist then you should manually create it.</b></li></ol> <p>Check if the module is installed correctly, from your PowerShell session type:</p> <div style="width:935px"> <blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; Get-Module -ListAvailable

ModuleType Name                      ExportedCommands
---------- ----                      ----------------
Manifest   ShareUtils                {}


PS C:\&gt;</p></span></font></pre></blockquote></div>
<p>If you don't see the above result then the module was not installed correctly. Make sure the module directory exists under &quot;%USERPROFILE%\Documents\WindowsPowerShell\Modules&quot;</p>
<p>Importing the module: </p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; Import-Module ShareUtils</p></span></font></pre></blockquote></div><b><font color="#ff0000">Note:</font></b> An elevated PowerShell session is needed to load the module. If the session is not elevated a warning message is written to the console and you won't be able to use any of the module’s functions. 
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; Get-Command -Module shareutils

CommandType     Name                                                Definition
-----------     ----                                                ----------
Filter          Add-SharePermission                                 ...
Function        Get-Share                                           ...
Function        New-Share                                           ...
Filter          Remove-Share                                        ...
Filter          Remove-SharePermission                              ...
Filter          Set-Share                                           ...
Filter          Set-SharePermission                                 ...


PS C:\&gt;</p></span></font></pre></blockquote></div>
<p>Each function (filter) has its own help. To get a help you may run the following command:</p>
<p>Get-Help &lt;FunctionName&gt;</p>
<p>And download link:</p>
<div>
<p style="border-bottom:silver 1px solid;position:relative;border-left:silver 1px solid;width:240px;height:66px;border-top:silver 1px solid;border-right:silver 1px solid"><span style="font-family:verdana,arial,sans-serif;cursor:pointer"><a style="border-bottom:0px;border-left:0px;width:240px;height:66px;border-top:0px;border-right:0px" href="/psscripts/ShareUtils.zip"><img style="border-bottom:0px;border-left:0px;width:240px;height:66px;border-top:0px;border-right:0px" alt="Download File" src="http://www.sysadmins.lv/images/buttons/transparent.gif"> </a><a style="border-bottom:0px;border-left:0px;border-top:0px;border-right:0px" href="/psscripts/ShareUtils.zip"><img style="border-bottom:0px;position:absolute;border-left:0px;border-top:0px;top:6px;border-right:0px;left:5px" alt="Download File" src="http://www.sysadmins.lv/images/buttons/zip.png" width=48 height=45> </a><a style="text-decoration:none" href="/psscripts/ShareUtils.zip"><span style="position:absolute;width:167px;white-space:nowrap;color:#555555;overflow:hidden;top:7px;margin-right:5px;left:67px"><span style="display:block;visibility:hidden">1</span> <span style="line-height:1.25em;display:block;cursor:pointer;text-decoration:none;padding-top:1px" title="Download file">ZIP file <br>66,4 KB </span></span></a><a style="position:absolute;width:167px;white-space:nowrap;color:#0066a7;overflow:hidden;top:7px;margin-right:5px;text-decoration:none;left:67px" href="/psscripts/ShareUtils.zip">ShareUtils.zip</a> </span></p></div></div></div>
<div><b>Category:</b> PowerShell</div>
<div><b>Published:</b> 2010.10.29. 10:47</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PowerShell</category>
      <pubDate>Fri, 29 Oct 2010 07:47:25 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=28</guid>
    </item>
    <item>
      <title>Get registered CNG CSPs on the system</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=47</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass6139B93259FE4F8E8B37B723852E1101><p>Some time ago I've posted a simple code example that will retrieve registered CSPs: <a href="/Lists/Posts/Post.aspx?ID=37">Get registered CSPs on the system</a>. The code was updated to provide detailed information about supported algorithms and protocols by particular CSP. Updated version of this code is shipped with my PowerShell PKI module as a <a href="http://pspki.codeplex.com/wikipage?title=Get-CryptographicServiceProvider"><nobr>Get-CryptographicServiceProvider</nobr></a> cmdlet. The output is pretty informative:</p> <div style="width:935px"> <blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; $CSP[1]

Name                                          Type                                     SupportedAlgorithms
----                                          ----                                     -------------------
Microsoft Base Cryptographic Provider v1.0    RSA Full (Signature and Key Exchange)    {RC2, RC4, DES, SHA-1...}


PS C:\&gt; $CSP[1].SupportedAlgorithms

Name                 DefaultKeyLength MinKeyLength     MaxKeyLength     Protocols
----                 ---------------- ------------     ------------     ---------
RC2                  40               40               56
RC4                  40               40               56
DES                  56               56               56
SHA-1                160              160              160              {Signing protocol}
MD2                  128              128              128              {Signing protocol}
MD4                  128              128              128              {Signing protocol}
MD5                  128              128              128              {Signing protocol}
SSL3 SHAMD5          288              288              288
MAC                  0                0                0
RSA_SIGN             512              384              16384            {Internet protocol security (IPsec) protocol...
RSA_KEYX             512              384              1024             {Internet protocol security (IPsec) protocol...
HMAC                 0                0                0


PS C:\&gt;</p></span></font></pre></blockquote></div>
<p>However existing code is limited to legacy CSPs and do not support any CNG (Cryptography Next Generation) CSPs. To address this limitation I wrote another function for CNG providers. As usually the code uses p/invoke to get required information:</p>
<blockquote><pre style="line-height:normal;font-variant:normal;font-style:normal;font-size:9pt;font-weight:normal"><span style="color:#800080">$ncryptsignature</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">@'
</span><span style="color:#800000">[DllImport(&quot;ncrypt.dll&quot;, SetLastError = true)]
public static extern uint NCryptEnumStorageProviders(
    ref uint pImplCount,
    ref IntPtr ppImplList,
    uint dwFlags
);
[DllImport(&quot;ncrypt.dll&quot;, SetLastError = true)]
public static extern uint NCryptOpenStorageProvider(
    ref IntPtr phProvider,
    [MarshalAs(UnmanagedType.LPWStr)] string pszProviderName,
    uint dwFlags
);
[DllImport(&quot;ncrypt.dll&quot;, SetLastError = true)]
public static extern uint NCryptEnumAlgorithms(
    IntPtr hProvider,
    uint dwAlgOperations,
    ref int pdwAlgCount,
    ref IntPtr ppAlgList,
    uint dwFlags
);
[DllImport(&quot;ncrypt.dll&quot;, SetLastError = true)]
public static extern uint NCryptFreeBuffer(
    IntPtr pvInput
);
[DllImport(&quot;ncrypt.dll&quot;, SetLastError = true)]
public static extern uint NCryptFreeObject(
    IntPtr phProvider
);

[StructLayout(LayoutKind.Sequential)]
public struct NCryptProviderName {
    [MarshalAs(UnmanagedType.LPWStr)] public string pszName;
    [MarshalAs(UnmanagedType.LPWStr)] public string pszComment;
};
[StructLayout(LayoutKind.Sequential)]
public struct NCryptAlgorithmName {
    [MarshalAs(UnmanagedType.LPWStr)] public string pszName;
    public uint dwClass;
    public uint dwAlgOperations;
    public uint dwFlags;
};
</span><span style="color:#800000">'@</span><span style="color:#000000">

</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="color:#800000">@'
</span><span style="color:#800000">namespace PKI {
    namespace ServiceProviders {
        public class CspCNG {
            public string Name;
            public string Comments;
            public ALG_ID_CNG[] SupportedAlgorithms;
        }
        public class ALG_ID_CNG {
            public string Name;
            public string Interface;
            public string[] Operations;
        }
    }
}
</span><span style="color:#800000">'@</span><span style="color:#000000">
</span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Add-Type</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-MemberDefinition</span><span style="color:#000000"> </span><span style="color:#800080">$ncryptsignature</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Namespace</span><span style="color:#000000"> </span><span style="color:#800000">PKI</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Name</span><span style="color:#000000"> </span><span style="color:#800000">nCrypt</span><span style="color:#000000">}
</span><span style="color:#0000ff">catch</span><span style="color:#000000"> {</span><span style="color:#800080">$NoCNG</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">; </span><span style="color:#0000ff">return</span><span style="color:#000000">}

</span><span style="color:#0000ff">#region</span><span style="color:#000000"> enumerations
    </span><span style="color:#800080">$Interface</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> @{</span><span style="color:#000000">3</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Asymmetric encryption</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#000000">4</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Secret agreement</span><span style="color:#800000">&quot;</span><span style="color:#000000">;
        </span><span style="color:#000000">5</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Signature interface</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#000000">0x00010001</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Key storage interface</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#000000">0x00010002</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">SChannel interface</span><span style="color:#800000">&quot;</span><span style="color:#000000">;
        </span><span style="color:#000000">0x00010003</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">SChannel signature interface</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
</span><span style="color:#0000ff">#endregion</span><span style="color:#000000">

[</span><span style="color:#008080">UInt32</span><span style="color:#000000">]</span><span style="color:#800080">$pImplCount</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
[</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$ppImplList</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
</span><span style="color:#800080">$Return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">]::</span><span style="color:#8b4513">NCryptEnumStorageProviders</span><span style="color:#000000">([</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pImplCount</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$ppImplList</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)
</span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#ff0000">!</span><span style="color:#800080">$Return</span><span style="color:#000000">) {
</span><span style="color:#800080">$pvInput</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$ppImplList</span><span style="color:#000000">
    </span><span style="color:#800080">$Names</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> $(</span><span style="color:#0000ff">for</span><span style="color:#000000"> (</span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">; </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#800080">$pImplCount</span><span style="color:#000000">; </span><span style="color:#800080">$n</span><span style="color:#000000">++) {
        [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">PtrToStructure</span><span style="color:#000000">(</span><span style="color:#800080">$ppImplList</span><span style="color:#000000">,[</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">+NCryptProviderName])
        [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$ppImplList</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$ppImplList</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">SizeOf</span><span style="color:#000000">([</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">+NCryptProviderName])
    }) | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{</span><span style="color:#000080">$_</span><span style="color:#000000">.pszName}
    [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">]::</span><span style="color:#8b4513">NCryptFreeBuffer</span><span style="color:#000000">(</span><span style="color:#800080">$pvInput</span><span style="color:#000000">)
} </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">The handle is invalid.</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
</span><span style="color:#0000ff">foreach</span><span style="color:#000000"> (</span><span style="color:#800080">$pszProviderName</span><span style="color:#000000"> </span><span style="color:#0000ff">in</span><span style="color:#000000"> </span><span style="color:#800080">$Names</span><span style="color:#000000">) {
    </span><span style="color:#800080">$CSP</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">PKI.ServiceProviders.CspCNG</span><span style="color:#000000">
    </span><span style="color:#800080">$CSP</span><span style="color:#000000">.</span><span style="color:#8b4513">Name</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$pszProviderName</span><span style="color:#000000">
    [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$phProvider</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
    </span><span style="color:#800080">$Return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">]::</span><span style="color:#8b4513">NCryptOpenStorageProvider</span><span style="color:#000000">([</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$phProvider</span><span style="color:#000000">,</span><span style="color:#800080">$pszProviderName</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#ff0000">!</span><span style="color:#800080">$Return</span><span style="color:#000000">) {
        </span><span style="color:#800080">$pdwAlgCount</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
        </span><span style="color:#800080">$ppAlgList</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]::</span><span style="color:#8b4513">Zero</span><span style="color:#000000">
        </span><span style="color:#800080">$dwAlgOperations</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0x0</span><span style="color:#000000">
        </span><span style="color:#800080">$Return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">]::</span><span style="color:#8b4513">NCryptEnumAlgorithms</span><span style="color:#000000">(</span><span style="color:#800080">$phProvider</span><span style="color:#000000">,</span><span style="color:#800080">$dwAlgOperations</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$pdwAlgCount</span><span style="color:#000000">,[</span><span style="color:#008080">ref</span><span style="color:#000000">]</span><span style="color:#800080">$ppAlgList</span><span style="color:#000000">,</span><span style="color:#000000">0</span><span style="color:#000000">)
        </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#ff0000">!</span><span style="color:#800080">$Return</span><span style="color:#000000">) {
            </span><span style="color:#800080">$pvInput</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$ppAlgList</span><span style="color:#000000">
            </span><span style="color:#0000ff">for</span><span style="color:#000000"> (</span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">; </span><span style="color:#800080">$n</span><span style="color:#000000"> </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#800080">$pdwAlgCount</span><span style="color:#000000">; </span><span style="color:#800080">$n</span><span style="color:#000000">++) {
                </span><span style="color:#800080">$AlgID</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">PtrToStructure</span><span style="color:#000000">(</span><span style="color:#800080">$ppAlgList</span><span style="color:#000000">,[</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">+NCryptAlgorithmName])
                </span><span style="color:#800080">$options</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">4</span><span style="color:#000000">,</span><span style="color:#000000">8</span><span style="color:#000000">,</span><span style="color:#000000">16</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{[</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$AlgID</span><span style="color:#000000">.dwAlgOperations </span><span style="color:#ff0000">-band</span><span style="color:#000000"> </span><span style="color:#000080">$_</span><span style="color:#000000">} | ?{</span><span style="color:#000080">$_</span><span style="color:#000000">}
                </span><span style="color:#800080">$Alg</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">PKI.ServiceProviders.ALG_ID_CNG</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Property</span><span style="color:#000000"> @{
                    Name </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$AlgID</span><span style="color:#000000">.pszName
                    Interface </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Interface</span><span style="color:#000000">[[</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$AlgID</span><span style="color:#000000">.dwClass]
                    Operations </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#0000ff">switch</span><span style="color:#000000"> (</span><span style="color:#800080">$options</span><span style="color:#000000">) {
                        </span><span style="color:#000000">4</span><span style="color:#000000"> {</span><span style="color:#800000">&quot;</span><span style="color:#800000">Asymmetric encryption</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
                        </span><span style="color:#000000">8</span><span style="color:#000000"> {</span><span style="color:#800000">&quot;</span><span style="color:#800000">Secret agreement</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
                        </span><span style="color:#000000">16</span><span style="color:#000000"> {</span><span style="color:#800000">&quot;</span><span style="color:#800000">Signature</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
                    }
                }
                </span><span style="color:#800080">$CSP</span><span style="color:#000000">.</span><span style="color:#8b4513">SupportedAlgorithms</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$Alg</span><span style="color:#000000">
                [</span><span style="color:#008080">IntPtr</span><span style="color:#000000">]</span><span style="color:#800080">$ppAlgList</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$ppAlgList</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> [</span><span style="color:#008080">Runtime.InteropServices.Marshal</span><span style="color:#000000">]::</span><span style="color:#8b4513">SizeOf</span><span style="color:#000000">([</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">+NCryptAlgorithmName])
            }
            </span><span style="color:#800080">$CSP</span><span style="color:#000000">
            [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">]::</span><span style="color:#8b4513">NCryptFreeBuffer</span><span style="color:#000000">(</span><span style="color:#800080">$pvInput</span><span style="color:#000000">)
        } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Parameter is incorrect.</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
        [</span><span style="color:#008080">void</span><span style="color:#000000">][</span><span style="color:#008080">PKI.nCrypt</span><span style="color:#000000">]::</span><span style="color:#8b4513">NCryptFreeObject</span><span style="color:#000000">(</span><span style="color:#800080">$phProvider</span><span style="color:#000000">)
    } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">The handle is invalid.</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
}</span></pre></blockquote>
<p>And here is output information:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p>PS C:\&gt; $CSP = Get-CSP
PS C:\&gt; $CSP

Name                                    Comments                                SupportedAlgorithms
----                                    --------                                -------------------
Microsoft Software Key Storage Provider                                         {RSA, DH, DSA, ECDH_P256...}
Microsoft Smart Card Key Storage Pro...                                         {RSA, ECDH_P256, ECDH_P384, ECDH_P52...


PS C:\&gt; $CSP[0].SupportedAlgorithms

Name                                    Interface                               Operations
----                                    ---------                               ----------
RSA                                     Asymmetric encryption                   {Asymmetric encryption, Signature}
DH                                      Secret agreement                        {Secret agreement}
DSA                                     Signature interface                     {Signature}
ECDH_P256                               Secret agreement                        {Secret agreement, Signature}
ECDH_P384                               Secret agreement                        {Secret agreement, Signature}
ECDH_P521                               Secret agreement                        {Secret agreement, Signature}
ECDSA_P256                              Signature interface                     {Signature}
ECDSA_P384                              Signature interface                     {Signature}
ECDSA_P521                              Signature interface                     {Signature}


PS C:\&gt;</p></span></font></pre></blockquote></div>
<p>Currently Microsoft provides only 2 CNG crypto providers: <strong>Microsoft Software Key Storage Provider</strong> and <strong>Microsoft Smart Card Key Storage Provider</strong>. I'll include this sample to my PS PKI module next release.</p></div></div>
<div><b>Category:</b> PKI;CryptoAPI</div>
<div><b>Published:</b> 2011.08.06. 22:28</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;CryptoAPI</category>
      <pubDate>Sat, 06 Aug 2011 19:28:29 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=47</guid>
    </item>
    <item>
      <title>How to convert PEM file to a CryptoAPI compatible format</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=46</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClassE51FFAFC29D04715B7F3701BA8EA3E8B><p>Hello again. Continuing the previous post: <a href="/Lists/Posts/Post.aspx?ID=45">How to join certificate and private key to a PKCS#12(PFX) file</a> I'll talk a bit more about certutil.exe and openssl.exe private key formats and it differences. Let's start:</p> <ul> <li>OpenSSL is big-endian by a nature, Microsoft CryptoAPI — little-endian;  <li>OpenSSL uses ASN.1 structures, but Microsoft CryptoAPI — unmanaged C++-like structures.</li></ul> <p>Here is a structure type definition for <a href="http://www.rsa.com/rsalabs/node.asp?id=2125">PKCS#1</a> private key structure:</p> <blockquote><pre style="font-size:12px"><font color="#0000ff">RSAPrivateKey ::= SEQUENCE {
	version Version,
	modulus INTEGER, -- n
	publicExponent INTEGER, -- e
	privateExponent INTEGER, -- d
	prime1 INTEGER, -- p
	prime2 INTEGER, -- q
	exponent1 INTEGER, -- d mod (p-1)
	exponent2 INTEGER, -- d mod (q-1)
	coefficient INTEGER, -- (inverse of q) mod p
	otherPrimeInfos OtherPrimeInfos OPTIONAL
}</font></pre></blockquote>
<p>Also it may use PKCS#8 structure (as per <a href="http://tools.ietf.org/html/rfc5208">RFC 5208</a>):</p>
<blockquote><pre style="font-size:12px"><font color="#0000ff">PrivateKeyInfo ::= SEQUENCE {
   version Version,
   privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
   privateKey PrivateKey,
   attributes [0] Attributes OPTIONAL }

Version ::= INTEGER {v1(0)} (v1,...)

PrivateKey ::= OCTET STRING

Attributes ::= SET OF Attribute</font></pre></blockquote>
<p>Microsoft CryptoAPI uses different structures (as per <a href="http://msdn.microsoft.com/en-us/library/aa387401(VS.85).aspx">Private Key BLOBs</a>):</p>
<blockquote><pre style="font-size:12px"><font color="#0000ff">BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];

typedef struct _PUBLICKEYSTRUC {
  BYTE   bType;
  BYTE   bVersion;
  WORD   reserved;
  ALG_ID aiKeyAlg;
} BLOBHEADER, PUBLICKEYSTRUC;

typedef struct _RSAPUBKEY {
  DWORD magic;
  DWORD bitlen;
  DWORD pubexp;
} RSAPUBKEY;</font></pre></blockquote>
<p>As you can see these structures are really different and you need to use multiple tools for the same task. To address this issue I wrote a simple converter that will convert PKCS#1 or PKCS#8 private key structures to a CryptoAPI structures. Here is a code:</p>
<blockquote><pre><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Convert-OpenSSLPrivateKey</span><span style="color:#000000"> {
[CmdletBinding()]
    </span><span style="color:#0000ff">param</span><span style="color:#000000">(
        [Parameter(Mandatory </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">, Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">)]
        [</span><span style="color:#008080">string</span><span style="color:#000000">]</span><span style="color:#800080">$InputPath</span><span style="color:#000000">,
        [Parameter(Mandatory </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000080">$true</span><span style="color:#000000">, Position </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
        [</span><span style="color:#008080">string</span><span style="color:#000000">]</span><span style="color:#800080">$OutputPath</span><span style="color:#000000">
    )
    </span><span style="color:#800080">$File</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">Get-Item</span><span style="color:#000000"> </span><span style="color:#800080">$InputPath</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Force</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ErrorAction</span><span style="color:#000000"> </span><span style="color:#800000">Stop</span><span style="color:#000000">
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$PSBoundParameters</span><span style="color:#000000">.Debug) {</span><span style="color:#000080">$DebugPreference</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">continue</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
    </span><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> (</span><span style="color:#800080">$RawData</span><span style="color:#000000">, </span><span style="color:#800080">$offset</span><span style="color:#000000">) {
        </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;&quot;</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">Select</span><span style="color:#000000"> FullLength, Padding, LengthBytes, </span><span style="color:#800000">PayLoadLength</span><span style="color:#000000">
        </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$RawData</span><span style="color:#000000">[</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">] </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#000000">128</span><span style="color:#000000">) {
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">lengthbytes</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">Padding</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$RawData</span><span style="color:#000000">[</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">]
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">Padding</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">lengthbytes</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">
        } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">lengthbytes</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$RawData</span><span style="color:#000000">[</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">] </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">128</span><span style="color:#000000">
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">Padding</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">
            </span><span style="color:#800080">$lengthstring</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#ff0000">-join</span><span style="color:#000000"> (</span><span style="color:#800080">$RawData</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">2</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">lengthbytes</span><span style="color:#000000">)] | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{</span><span style="color:#800000">&quot;</span><span style="color:#800000">{0:x2}</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-f</span><span style="color:#000000"> </span><span style="color:#000080">$_</span><span style="color:#000000">})
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">Invoke-Expression</span><span style="color:#000000"> 0x$(</span><span style="color:#800080">$lengthstring</span><span style="color:#000000">)
            </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">Padding</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">lengthbytes</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">
        }
        </span><span style="color:#800080">$return</span><span style="color:#000000">
    }

    </span><span style="color:#0000ff">function</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> (</span><span style="color:#800080">$array</span><span style="color:#000000">) {
        </span><span style="color:#800080">$Powers</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">.</span><span style="color:#000000">.12</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{[</span><span style="color:#008080">Math</span><span style="color:#000000">]::</span><span style="color:#8b4513">Pow</span><span style="color:#000000">(</span><span style="color:#000000">2</span><span style="color:#000000">,</span><span style="color:#000080">$_</span><span style="color:#000000">)}
        </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Powers</span><span style="color:#000000"> </span><span style="color:#ff0000">-notcontains</span><span style="color:#000000"> </span><span style="color:#800080">$array</span><span style="color:#000000">.Length) {
            </span><span style="color:#800080">$MatchPower</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Powers</span><span style="color:#000000"> </span><span style="color:#ff0000">-lt</span><span style="color:#000000"> </span><span style="color:#800080">$array</span><span style="color:#000000">.Length | </span><span style="color:#5f9ea0;font-weight:bold">select</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Last</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">
            </span><span style="color:#800080">$array</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$array</span><span style="color:#000000">[(</span><span style="color:#800080">$array</span><span style="color:#000000">.Length </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$MatchPower</span><span style="color:#000000">)..(</span><span style="color:#800080">$array</span><span style="color:#000000">.Length </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
        }
        [</span><span style="color:#008080">array</span><span style="color:#000000">]::</span><span style="color:#8b4513">Reverse</span><span style="color:#000000">(</span><span style="color:#800080">$array</span><span style="color:#000000">)
        [</span><span style="color:#008080">Byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$array</span><span style="color:#000000">
    }
    </span><span style="color:#008000">#</span><span style="color:#008000"> parse content</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#800080">$Text</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IO.File</span><span style="color:#000000">]::</span><span style="color:#8b4513">ReadAllText</span><span style="color:#000000">(</span><span style="color:#800080">$File</span><span style="color:#000000">)
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Extracting certificate information...</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Text</span><span style="color:#000000"> </span><span style="color:#ff0000">-match</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">(?msx).*-{5}BEGIN\sCERTIFICATE-{5}(.+)-{5}END\sCERTIFICATE-{5}</span><span style="color:#800000">&quot;</span><span style="color:#000000">) {
        </span><span style="color:#800080">$RawData</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Convert</span><span style="color:#000000">]::</span><span style="color:#8b4513">FromBase64String</span><span style="color:#000000">(</span><span style="color:#000080">$Matches</span><span style="color:#000000">[1])
        </span><span style="color:#0000ff">try</span><span style="color:#000000"> {</span><span style="color:#800080">$Cert</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> </span><span style="color:#800000">Security.Cryptography.X509Certificates.X509Certificate2</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> @(,</span><span style="color:#800080">$RawData</span><span style="color:#000000">)}
        </span><span style="color:#0000ff">catch</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">The data is invalid.</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#0000ff">return</span><span style="color:#000000">}
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">X.509 certificate is correct.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    } </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Missing certificate file.</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#0000ff">return</span><span style="color:#000000">}
    </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Text</span><span style="color:#000000"> </span><span style="color:#ff0000">-match</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">(?msx).*-{5}BEGIN\sPRIVATE\sKEY-{5}(.+)-{5}END\sPRIVATE\sKEY-{5}</span><span style="color:#800000">&quot;</span><span style="color:#000000">) {
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Processing Private Key module.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Convert</span><span style="color:#000000">]::</span><span style="color:#8b4513">FromBase64String</span><span style="color:#000000">(</span><span style="color:#000080">$matches</span><span style="color:#000000">[1])
        </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Bytes</span><span style="color:#000000">[0] </span><span style="color:#ff0000">-eq</span><span style="color:#000000"> </span><span style="color:#000000">48</span><span style="color:#000000">) {</span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Starting asn.1 decoding.</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
        </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">The data is invalid.</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#0000ff">return</span><span style="color:#000000">}
        </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
        </span><span style="color:#008000">#</span><span style="color:#008000"> main sequence</span><span style="color:#008000">
</span><span style="color:#000000">        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process outer Sequence tag.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">outer Sequence length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayloadLength</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#008000">#</span><span style="color:#008000"> zero integer</span><span style="color:#008000">
</span><span style="color:#000000">        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process zero byte</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">outer zero byte length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#008000">#</span><span style="color:#008000"> algorithm identifier</span><span style="color:#008000">
</span><span style="color:#000000">        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Proess algorithm identifier</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Algorithm identifier length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#008000">#</span><span style="color:#008000"> octet string</span><span style="color:#008000">
</span><span style="color:#000000">        </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Private key octet string length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    } </span><span style="color:#0000ff">elseif</span><span style="color:#000000"> (</span><span style="color:#800080">$Text</span><span style="color:#000000"> </span><span style="color:#ff0000">-match</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">(?msx).*-{5}BEGIN\sRSA\sPRIVATE\sKEY-{5}(.+)-{5}END\sRSA\sPRIVATE\sKEY-{5}</span><span style="color:#800000">&quot;</span><span style="color:#000000">) {
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Processing RSA KEY module.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
        </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Convert</span><span style="color:#000000">]::</span><span style="color:#8b4513">FromBase64String</span><span style="color:#000000">(</span><span style="color:#000080">$matches</span><span style="color:#000000">[1])
        </span><span style="color:#0000ff">if</span><span style="color:#000000"> (</span><span style="color:#800080">$Bytes</span><span style="color:#000000">[0] </span><span style="color:#ff0000">-eq</span><span style="color:#000000"> </span><span style="color:#000000">48</span><span style="color:#000000">) {</span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Starting asn.1 decoding</span><span style="color:#800000">&quot;</span><span style="color:#000000">}
        </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">The data is invalid</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#0000ff">return</span><span style="color:#000000">}
        </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0</span><span style="color:#000000">
        </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    }  </span><span style="color:#0000ff">else</span><span style="color:#000000"> {</span><span style="color:#5f9ea0;font-weight:bold">Write-Warning</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">The data is invalid</span><span style="color:#800000">&quot;</span><span style="color:#000000">; </span><span style="color:#0000ff">return</span><span style="color:#000000">}
    </span><span style="color:#008000">#</span><span style="color:#008000"> private key sequence</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process private key sequence.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Private key length (including inner ASN.1 tags) is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> zero integer</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process zero byte</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Zero byte length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> modulus</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Processing private key modulus.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Private key modulus length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$modulus</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$modulus</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$modulus</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> public exponent</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process private key public exponent.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Private key public exponent length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Private key public exponent padding is $(4 - $return.PayLoadLength) byte(s).</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$padding</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">New-Object</span><span style="color:#000000"> byte[] </span><span style="font-style:italic;color:#5f9ea0">-ArgumentList</span><span style="color:#000000"> (</span><span style="color:#000000">4</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)
    [</span><span style="color:#008080">Byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$PublicExponent</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$padding</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> private exponent</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process private key private exponent.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Private key private exponent length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$PrivateExponent</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$PrivateExponent</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$PrivateExponent</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> prime1</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process Prime1.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Prime1 length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$Prime1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$Prime1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$Prime1</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> prime2</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process Prime2.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Prime2 length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$Prime2</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$Prime2</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$Prime2</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> exponent1</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process Exponent1.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Exponent1 length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$Exponent1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$Exponent1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$Exponent1</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> exponent2</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process Exponent2.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Exponent2 length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$Exponent2</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$Exponent2</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$Exponent2</span><span style="color:#000000">
    </span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+=</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">New offset is: $offset</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#008000">#</span><span style="color:#008000"> coefficient</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Process Coefficient.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$return</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-ASNLength</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000"> </span><span style="color:#800080">$offset</span><span style="color:#000000">
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Coeicient length is $($return.PayloadLength) bytes.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$Coefficient</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$Bytes</span><span style="color:#000000">[(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">PayLoadLength</span><span style="color:#000000">)..(</span><span style="color:#800080">$offset</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$return</span><span style="color:#000000">.</span><span style="color:#8b4513">FullLength</span><span style="color:#000000"> </span><span style="color:#ff0000">-</span><span style="color:#000000"> </span><span style="color:#000000">1</span><span style="color:#000000">)]
    </span><span style="color:#800080">$Coefficient</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0">Get-NormalizedArray</span><span style="color:#000000"> </span><span style="color:#800080">$Coefficient</span><span style="color:#000000">

    </span><span style="color:#008000">#</span><span style="color:#008000"> creating Private Key BLOB structure</span><span style="color:#008000">
</span><span style="color:#000000">    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Calculating key length.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$bitLen</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">{0:X4}</span><span style="color:#800000">&quot;</span><span style="color:#000000"> </span><span style="color:#ff0000">-f</span><span style="color:#000000"> $(</span><span style="color:#800080">$modulus</span><span style="color:#000000">.</span><span style="color:#8b4513">Length</span><span style="color:#000000"> </span><span style="color:#ff0000">*</span><span style="color:#000000"> </span><span style="color:#000000">8</span><span style="color:#000000">)
    </span><span style="color:#5f9ea0;font-weight:bold">Write-Debug</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">Key length is $($modulus.Length * 8) bits.</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    [</span><span style="color:#008080">byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$bitLen1</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">iex</span><span style="color:#000000"> 0x$([</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$bitLen</span><span style="color:#000000">.</span><span style="color:#8b4513">Substring</span><span style="color:#000000">(</span><span style="color:#000000">0</span><span style="color:#000000">,</span><span style="color:#000000">2</span><span style="color:#000000">))
    [</span><span style="color:#008080">byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$bitLen2</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">iex</span><span style="color:#000000"> 0x$([</span><span style="color:#008080">int</span><span style="color:#000000">]</span><span style="color:#800080">$bitLen</span><span style="color:#000000">.</span><span style="color:#8b4513">Substring</span><span style="color:#000000">(</span><span style="color:#000000">2</span><span style="color:#000000">,</span><span style="color:#000000">2</span><span style="color:#000000">))
    [</span><span style="color:#008080">Byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$PrivateKey</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#000000">0x07</span><span style="color:#000000">,</span><span style="color:#000000">0x02</span><span style="color:#000000">,</span><span style="color:#000000">0x00</span><span style="color:#000000">,</span><span style="color:#000000">0x00</span><span style="color:#000000">,</span><span style="color:#000000">0x00</span><span style="color:#000000">,</span><span style="color:#000000">0x24</span><span style="color:#000000">,</span><span style="color:#000000">0x00</span><span style="color:#000000">,</span><span style="color:#000000">0x00</span><span style="color:#000000">,</span><span style="color:#000000">0x52</span><span style="color:#000000">,</span><span style="color:#000000">0x53</span><span style="color:#000000">,</span><span style="color:#000000">0x41</span><span style="color:#000000">,</span><span style="color:#000000">0x32</span><span style="color:#000000">,</span><span style="color:#000000">0x00</span><span style="color:#000000">
    [</span><span style="color:#008080">Byte</span><span style="color:#000000">[]]</span><span style="color:#800080">$PrivateKey</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$PrivateKey</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$bitLen1</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$bitLen2</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$PublicExponent</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> ,</span><span style="color:#000000">0x00</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#5f9ea0;font-weight:bold">`</span><span style="color:#000000">
    </span><span style="color:#800080">$modulus</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$Prime1</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$Prime2</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$Exponent1</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$Exponent2</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$Coefficient</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800080">$PrivateExponent</span><span style="color:#000000">
    </span><span style="color:#800080">$Base</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">Convert</span><span style="color:#000000">]::</span><span style="color:#8b4513">ToBase64String</span><span style="color:#000000">(</span><span style="color:#800080">$PrivateKey</span><span style="color:#000000">)
    </span><span style="color:#800080">$TempFile</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> [</span><span style="color:#008080">IO.Path</span><span style="color:#000000">]::</span><span style="color:#8b4513">GetTempFileName</span><span style="color:#000000">()
    </span><span style="color:#800080">$CertFileName</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$TempFile</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">.cer</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    </span><span style="color:#800080">$KeyFileName</span><span style="color:#000000"> </span><span style="color:#ff0000">=</span><span style="color:#000000"> </span><span style="color:#800080">$TempFile</span><span style="color:#000000"> </span><span style="color:#ff0000">+</span><span style="color:#000000"> </span><span style="color:#800000">&quot;</span><span style="color:#800000">.key</span><span style="color:#800000">&quot;</span><span style="color:#000000">
    [</span><span style="color:#008080">IO.File</span><span style="color:#000000">]::</span><span style="color:#8b4513">WriteAllBytes</span><span style="color:#000000">(</span><span style="color:#800080">$CertFileName</span><span style="color:#000000">, </span><span style="color:#800080">$Cert</span><span style="color:#000000">.RawData)
    </span><span style="color:#5f9ea0;font-weight:bold">Set-Content</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Path</span><span style="color:#000000"> </span><span style="color:#800080">$KeyFileName</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Value</span><span style="color:#000000"> </span><span style="color:#800080">$Base</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Encoding</span><span style="color:#000000"> </span><span style="color:#800000">Ascii</span><span style="color:#000000">
    certutil </span><span style="color:#ff0000">-f</span><span style="color:#000000"> -MergePFX </span><span style="color:#800080">$CertFileName</span><span style="color:#000000"> </span><span style="color:#800080">$OutputPath</span><span style="color:#000000">
    </span><span style="color:#800080">$TempFile</span><span style="color:#000000">, </span><span style="color:#800080">$CertFileName</span><span style="color:#000000">, </span><span style="color:#800080">$KeyFileName</span><span style="color:#000000"> | </span><span style="color:#5f9ea0;font-weight:bold">%</span><span style="color:#000000">{</span><span style="color:#5f9ea0;font-weight:bold">del</span><span style="color:#000000"> </span><span style="color:#000080">$_</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-Force</span><span style="color:#000000">}
}</span></pre></blockquote>
<p>I'm using a custom ASN.1 parser to get required data. The following syntax should be used:</p>
<blockquote><pre><span style="color:#5f9ea0">Convert-OpenSSLPrivateKey</span><span style="color:#000000"> </span><span style="font-style:italic;color:#5f9ea0">-InputPath</span><span style="color:#000000"> </span><span style="color:#800000">path\file</span><span style="color:#000000">.pem </span><span style="font-style:italic;color:#5f9ea0">-OutputPath</span><span style="color:#000000"> </span><span style="color:#800000">path\file</span><span style="color:#000000">.pfx</span></pre></blockquote>
<p>PEM file must be in the following format:</p>
<blockquote><pre style="font-size:12px"><font color="#0000ff">-----BEGIN PRIVATE KEY-----
&lt;some Base64 content&gt;
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
&lt;some Base64 content&gt;
-----END CERTIFICATE-----</font></pre></blockquote>
<p>or</p>
<blockquote><pre style="font-size:12px"><font color="#0000ff">-----BEGIN RSA PRIVATE KEY-----
&lt;some Base64 content&gt;
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
&lt;some Base64 content&gt;
-----END CERTIFICATE-----</font></pre></blockquote>
<p>if you have separate files (.pem and .key) you need to ensure if key file is not already compatible for certutil by running the command:</p>
<div style="width:935px">
<blockquote><pre style="background-color:#000040;font:9pt consolas, lucida console"><font color="#c0c0c0"><span><p><font color="#ff0000">[↓]</font> [vPodans] certutil -dump .\Desktop\1.txt
Private Key:
  PRIVATEKEYBLOB
  Version: 2
  aiKeyAlg: 0x2400
    CALG_RSA_SIGN
    Algorithm Class: 0x2000(1) ALG_CLASS_SIGNATURE
    Algorithm Type: 0x400(2) ALG_TYPE_RSA
    Algorithm Sub-id: 0x0(0) ALG_SID_RSA_ANY
  0000  52 53 41 32                                        RSA2
  0000  ...
  024c
CertUtil: -dump command completed successfully.
<font color="#ff0000">[↓]</font> [vPodans]</p></span></font></pre></blockquote></div>
<p>If your output is not like this you may try to use my converter. In this case you must manually combine certificate and key files into a single file following file structures above.</p>
<p>In the code I extract both private key and certificate contents. Only private key structures are processed. Once CryptoAPI-compatible structure is ready I copy certificate content to a random file in the current user's Temp (%temp%) folder. Private key is encoded in the Base64 and saved in the same Temp folder with .KEY extension (as required for certutil). If all is ok, certutil will ask you for a new password for output PFX file. Upon function completion (regardless if successfully or not) temporary files are deleted from the Temp folder.</p>
<p>In order to make this job better I would like to hear about script usage experience and feedback.</p></div></div>
<div><b>Category:</b> PKI;CryptoAPI;ASN.1;PowerShell</div>
<div><b>Published:</b> 2011.07.16. 23:50</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI;CryptoAPI;ASN.1;PowerShell</category>
      <pubDate>Sat, 16 Jul 2011 20:50:08 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=46</guid>
    </item>
    <item>
      <title>How to join certificate and private key to a PKCS#12(PFX) file</title>
      <link>http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=45</link>
      <description><![CDATA[<div><b>Body:</b> <div class=ExternalClass52950BC15DC9414C9F208118A703FA89><p>Hello S-1-1-0, PowerShell Crypto Guy still here and today we will talk about the subject. Sometimes you have to use 3rd party applications/tools for certificate request generation. Some of them uses Windows certificate store to store request and a corresponding private keys, but others generates a request file and separate file with unencrypted private key. As a common example are makecert.exe and openssl.exe tools. These applications creates a request file (mostly with .CSR or .REQ file extension) and private key file (mostly with .KEY or .PVK file extension) for UNIX-like systems compatibility. Once certificate request is signed you get a standard X.509 certificate file.</p> <p>The problem occurs when you try to import this certificate to the Windows certificate store. Obviously it will be imported without private key because Certificate Import Wizard don't know anything about separate private key file. There are at least 3 tools that can join (or convert) these files to a single pkcs12/PFX file:</p> <ul> <li><a href="http://openssl.org/">OpenSSL</a>;</li> <li><a href="http://technet.microsoft.com/en-us/library/cc732443(v=WS.10).aspx">certutil</a>;</li> <li><a href="http://msdn.microsoft.com/en-us/library/ff550672(v=VS.85).aspx">pvk2pfx</a>;</li></ul> <p>The following syntax is used for OpenSSL:</p> <p><font color="#0000ff" face=Consolas>OpenSSL.exe pkcs12 –export –in certfile.cer –inkey certfile.key –out certfile.pfx</font></p> <p>Also here is online (web-based) version of OpenSSL tool: <a title="https://www.sslshopper.com/ssl-converter.html" href="https://www.sslshopper.com/ssl-converter.html">https://www.sslshopper.com/ssl-converter.html</a></p> <p>The following syntax is used for certutil:</p> <p><font color="#0000ff" face=Consolas>certutil –MergePFX certfile.cer certfile.pfx</font></p> <p>Since there is no way to specify private key file for –MergePFX parameter you must consider the following requirements:</p> <ul> <li>Private key file MUST have .KEY extension;</li> <li>certificate and private key files MUST have the same base file name (file name excluding extension);</li> <li>certificate and private key file must be placed in the same directory.</li></ul> <p>The following syntax is used for pvk2pfx:</p> <p><font color="#0000ff" face=Consolas>pvk2pfx –pvk certfile.pvk –spc certfile.cer –out certfile.pfx</font></p> <p>And the last what I want to tell here. Unfortunately there are no universal tool for all cases. This really depends on an application that was used for key file generation. For example a key file created by OpenSSL is not compatible with certutil and pvk2pfx. A key created by makecert is compatible with pvk2pfx only and so on.</p> <p>HTH</p></div></div>
<div><b>Category:</b> PKI</div>
<div><b>Published:</b> 2011.07.14. 23:13</div>
]]></description>
      <author>Vadims Podans</author>
      <category>PKI</category>
      <pubDate>Thu, 14 Jul 2011 20:13:40 GMT</pubDate>
      <guid isPermaLink="true">http://en-us.sysadmins.lv/Lists/Posts/ViewPost.aspx?ID=45</guid>
    </item>
  </channel>
</rss>
