Display X509Certificate with chain elements not in certificate store #70
                  
                    
                      marcialwushu
                    
                  
                
                  started this conversation in
                General
              
            Replies: 3 comments
-
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPTUI_VIEWCERTIFICATE_STRUCT
{
    public int dwSize;
    public IntPtr hwndParent;
    public int dwFlags;
    [MarshalAs(UnmanagedType.LPWStr)]
    public String szTitle;
    public IntPtr pCertContext;
    public IntPtr rgszPurposes;
    public int cPurposes;
    public IntPtr pCryptProviderData;
    public Boolean fpCryptProviderDataTrustedUsage;
    public int idxSigner;
    public int idxCert;
    public Boolean fCounterSigner;
    public int idxCounterSigner;
    public int cStores;
    public IntPtr rghStores;
    public int cPropSheetPages;
    public IntPtr rgPropSheetPages;
    public int nStartPage;
}
public static class CryptAPI
{
    public static void ShowCertificateDialog(X509Chain chain, string title, IntPtr parent)
    {
        const int certStoreProvMemory = 2;      // CERT_STORE_PROV_MEMORY
        const int certCloseStoreCheckFlag = 2;  // CERT_CLOSE_STORE_CHECK_FLAG
        const uint certStoreAddAlways = 4;      // CERT_STORE_ADD_ALWAYS
        const uint x509AsnEncoding = 1;         // X509_ASN_ENCODING
        var storeHandle = CertOpenStore(certStoreProvMemory, 0, 0, 0, null);
        if (storeHandle == IntPtr.Zero)
            throw new Win32Exception();
        try
        {
            foreach (var element in chain.ChainElements)
            {
                var certificate = element.Certificate;
                var certificateBytes = certificate.Export(X509ContentType.Cert);
                var certContextHandle = CertCreateCertificateContext(
                    x509AsnEncoding, certificateBytes, (uint)certificateBytes.Length);
                if (certContextHandle == IntPtr.Zero)
                    throw new Win32Exception();
                CertAddCertificateContextToStore(storeHandle, certContextHandle, certStoreAddAlways, IntPtr.Zero);
            }
            var extraStoreArray = new[] { storeHandle };
            var extraStoreArrayHandle = GCHandle.Alloc(extraStoreArray, GCHandleType.Pinned);
            try
            {
                var extraStorePointer = extraStoreArrayHandle.AddrOfPinnedObject();
                var viewInfo = new CRYPTUI_VIEWCERTIFICATE_STRUCT();
                viewInfo.hwndParent = parent;
                viewInfo.dwSize = Marshal.SizeOf(viewInfo);
                viewInfo.pCertContext = chain.ChainElements[0].Certificate.Handle;
                viewInfo.szTitle = title;
                viewInfo.nStartPage = 0;
                viewInfo.cStores = 1;
                viewInfo.rghStores = extraStorePointer;
                var fPropertiesChanged = false;
                CryptUIDlgViewCertificate(ref viewInfo, ref fPropertiesChanged);
            }
            finally
            {
                if (extraStoreArrayHandle.IsAllocated)
                    extraStoreArrayHandle.Free();
            }
        }
        finally
        {
            CertCloseStore(storeHandle, certCloseStoreCheckFlag);
        }
    }
    [DllImport("CRYPT32", EntryPoint = "CertOpenStore", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern IntPtr CertOpenStore(int storeProvider, int encodingType, int hcryptProv, int flags, string pvPara);
    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CertCreateCertificateContext([In] uint dwCertEncodingType, [In] byte[] pbCertEncoded, [In] uint cbCertEncoded);
    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CertAddCertificateContextToStore([In] IntPtr hCertStore, [In] IntPtr pCertContext, [In] uint dwAddDisposition, [In, Out] IntPtr ppStoreContext);
    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CertFreeCertificateContext([In] IntPtr pCertContext);
    [DllImport("CRYPT32", EntryPoint = "CertCloseStore", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CertCloseStore(IntPtr storeProvider, int flags);
    [DllImport("CryptUI.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptUIDlgViewCertificate(ref CRYPTUI_VIEWCERTIFICATE_STRUCT pCertViewInfo, ref bool pfPropertiesChanged);
} | 
  
Beta Was this translation helpful? Give feedback.
                  
                    0 replies
                  
                
            -
        X509Certificate2 endCert = new X509Certificate2(
        Convert.FromBase64String(
            "MIIE8zCCA9ugAwIBAgIQSBDq+mlsLsCZqWMIWj/YADANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMVGhhd3RlLCBJbmMuMRYwFAYDVQQDEw1UaGF3dGUgU1NMIENBMB4XDTExMTI" + 
            "yMDAwMDAwMFoXDTE0MDIxNzIzNTk1OVowgYsxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxQLRm9yZXN0IEhpbGwxIzAhBgNVBAoUGkFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW" +
            "9uMRcwFQYDVQQLFA5JbmZyYXN0cnVjdHVyZTEVMBMGA1UEAxQMKi5hcGFjaGUub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApyhxElzdnWks7MMCEx24FMhHCbFcgKbO+fh/+JYrV91Cs" +
            "xsdqsAsvAU37P/eLMQ3ZVm93c6uQbt6cq+0VXniviFjXS3qUUJVUC60Q/YDzaYrTFZdY8ccA5wWdFTiMlJgwIqdlvB7JLkOzotvawRfJxeH+aucY756TdYGapAyno+3pWNXnU5sr1oaJ4uGchaS7LUAqpfP" +
            "fA3oTv63ZmIzHh2MTfDeUgdVSxeqEj3FCObLdps4Fs6c08Re2KAEZ+0UcMwNyJh0y6aP6PBgZAdt3qODONrI56TCDxjMC47lmIrm/U2Vy+v1LB90uU/1ESAiKvIKLjVZucO0U4Ol8VgiSDIH1FezXEhl+fP" + 
            "zY1N18u6kMx0AGDKDO0fBkUpkA6r6K4Kk/YvEJBLiIvLwLLnQhcwJjhRZItA52dNvKHMRYh5er1xVbLj7X+ujDfA6RpJYOmmPUxYzsZpZhTk0wybuGrkuvrm5t9ONP4p/2lan1G9aXqK6OLNh4W9IVUs1o1" +
            "KvMP86ToBOsZY/g50cld0kh7AMR+W/Lg9WtPxs1nq98k2J7HZBmMnYTEqwzSFtsMzGlqcFXO170JnfgklUjzi12vwQYO0bf/q+3e7QQsYRXzSGUEdKJZvzs0P09jJ6W/mDdnMdaoh7eYP5eynleZtElUgcd" +
            "NNgVAHn8NEUnJpwbGUCAwEAAaOBoDCBnTAMBgNVHRMBAf8EAjAAMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9zdnItb3YtY3JsLnRoYXd0ZS5jb20vVGhhd3RlT1YuY3JsMB0GA1UdJQQWMBQGCCsGAQUF" +
            "BwMBBggrBgEFBQcDAjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0ZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAA6BnlWlsAXvTmDpqijPpBUkD9Xkbys7UC/FOuUVr3P" +
            "K3d3GCQynwhooBe2CAshtxjb3Cc8zJfeqb5IQfjTcuEznIpONvqFvSmU4/INS+3/TPLoyQ81wpsIUbJzhhJY78CH8TZ5cn2BtWkI9fEydAXYe9a64GVdjPBJhneBon3J63s895GSSucQAIQZEiXBAqoklS5" +
            "n0Ud2aSYrNZJUVN3o8Rh0tvd0W2l6KjBaIZLUTieDZb3eRrValvjYDcCp9uI3aTdhht6zxUuE+OZ7DPWIWz3EYTMVTTtQdojJK9mM++JC74Y4s+JSCgRzTn3CxDMWPG5FWxavENub0FfsXfnY="));
        X509Certificate2 intermediateCA = new X509Certificate2(
        Convert.FromBase64String(
            "MIIEbDCCA1SgAwIBAgIQTV8sNAiyTCDNbVB+JE3J7DANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWN" + 
            "lcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTAwMjA4MDAwMD" + 
            "AwWhcNMjAwMjA3MjM1OTU5WjA8MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMVGhhd3RlLCBJbmMuMRYwFAYDVQQDEw1UaGF3dGUgU1NMIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmeSFW" + 
            "3ZJfS8F2MWsyMip09yY5tc0pi8M8iIm2KPJFEyPBaRF6BQMWJAFGrfFwQalgK+7HUlrUjSIw1nn72vEJ0GMK2Yd0OCjl5gZNEtB1ZjVxwWtouTX7QytT8G1sCH9PlBTssSQ0NQwZ2ya8Q50xMLciuiX/8mS" + 
            "rgGKVgqYMrAAI+yQGmDD7bs6yw9jnw1EyVLhJZa/7VCViX9WFLG3YR0cB4w6LPf/gN45RdWvGtF42MdxaqMZpzJQIenyDqHGEwNESNFmqFJX1xG0k4vlmZ9d53hR5U32t1m0drUJN00GOBN6HAiYXMRISst" + 
            "SoKn4sZ2Oe3mwIC88lqgRYke7EQIDAQABo4H7MIH4MDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AudGhhd3RlLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMDQGA1UdHwQtMCswKa" + 
            "AnoCWGI2h0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVQQ0EuY3JsMA4GA1UdDwEB/wQEAwIBBjAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVmVyaVNpZ25NUEtJLTItOTAdBgNVHQ4EFgQUp6KDuzRFQ" + 
            "D381TBPErk+oQGf9tswHwYDVR0jBBgwFoAUe1tFz6/Oy3r9MZIaarbzRutXSFAwDQYJKoZIhvcNAQEFBQADggEBAIAigOBsyJUW11cmh/NyNNvGclYnPtOW9i4lkaU+M5enS+Uv+yV9Lwdh+m+DdExMU3Ig" + 
            "pHrPUVFWgYiwbR82LMgrsYiZwf5Eq0hRfNjyRGQq2HGn+xov+RmNNLIjv8RMVR2OROiqXZrdn/0Dx7okQ40tR0Tb9tiYyLL52u/tKVxpEvrRI5YPv5wN8nlFUzeaVi/oVxBw9u6JDEmJmsEj9cIqzEHPIqt" + 
            "lbreUgm0vQF9Y3uuVK6ZyaFIZkSqudZ1OkubK3lTqGKslPOZkpnkfJn1h7X3S5XFV2JMXfBQ4MDzfhuNMrUnjl1nOG5srztxl1Asoa06ERlFE9zMILViXIa4="));
X509Chain chain = new X509Chain();
chain.ChainPolicy.ExtraStore.Add(intermediateCA);
chain.Build(endCert); // Whole chain!
X509Certificate2 fMainCertificate = null;
X509Certificate2Collection fExtraCertificates = new X509Certificate2Collection();
fMainCertificate = endCert;
fExtraCertificates.Add(intermediateCA);
X509Store lStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
// No need to write to the user's store, just read.
lStore.Open(OpenFlags.ReadOnly);
try
{
    List<X509Certificate2> lAddedCertificates = new List<X509Certificate2>();
    try
{
    foreach (X509Certificate2 lCertificate in fExtraCertificates)
        if (!lStore.Certificates.Contains(lCertificate))
    {
        lStore.Add(lCertificate);
            lAddedCertificates.Add(lCertificate);
        }
        X509Certificate2UI.DisplayCertificate(fMainCertificate);
}
    finally
{
    foreach (X509Certificate2 lCertificate in lAddedCertificates)
    lStore.Remove(lCertificate);
}
}
finally { lStore.Close(); } | 
  
Beta Was this translation helpful? Give feedback.
                  
                    0 replies
                  
                
            -
Beta Was this translation helpful? Give feedback.
                  
                    0 replies
                  
                
            
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
        
    
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I have an object of type
X509Certificate2and want to display it to the user. I'm doing this with theX509Certificate2UI.DisplayCertificatemethod.The problem I have is that this certificate I want to show is issued by an intermediate CA whichs certificate is not in the machines certificate store, but its root is.
Now if I display said certificate the dialog is not able to build the chain (opposite to me, as I am able to with the
X509Chainand the intermediate CA as an extra element)How do I display the certificate with the whole chain?
(I'm not able/allowed to add the intermediate CA to the user/machine store!)
(I'm not able/allowed to create my own dialog. It has to be the default Windows dialog!)
(P/Invoke is allowed if required)
Just as an example you can try these certificates to test above, but you have to reference
System.Security.dllforX509Certificate2UI.DisplayCertificate:I am confident that this should be somehow possible, as the Internet Explorer is doing the same. You can try it with https://httpd.apache.org/ (The certificates above are from there)
Beta Was this translation helpful? Give feedback.
All reactions