Retired Microsoft Blog disclaimer

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

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/02/13/how-to-view-a-certificate-programatically-c/
Post name: How to view a certificate programatically (C#)
Original author: Alejandro Campos Magencio
Posting date: 2009-02-13T03:36:00+00:00


Hi all,


The following C# sample shows a dialog to view a certificateand its properties. This is the same dialog that appears when we double-click on the cert file in Explorer. I'll use CryptUIDlgViewCertificate API and its CRYPTUI_VIEWCERTIFICATE_STRUCT structure to achieve this:

...
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;

namespace MyNamespace
{
public partial class MyClass
{
...
public const int CRYPTUI_DISABLE_ADDTOSTORE = 0x00000010;

[DllImport("CryptUI.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptUIDlgViewCertificate(
ref CRYPTUI_VIEWCERTIFICATE_STRUCT pCertViewInfo,
ref bool pfPropertiesChanged
);

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; // or hWVTStateData
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;
}

private void MySampleFunction()
{
// Get the cert
X509Certificate2 cert = new X509Certificate2(@"C:\temp\mycert.cer");

// Show the cert
CRYPTUI_VIEWCERTIFICATE_STRUCT certViewInfo = new CRYPTUI_VIEWCERTIFICATE_STRUCT();
certViewInfo.dwSize = Marshal.SizeOf(certViewInfo);
certViewInfo.pCertContext = cert.Handle;
certViewInfo.szTitle = "Certificate Info";
certViewInfo.dwFlags = CRYPTUI_DISABLE_ADDTOSTORE;
certViewInfo.nStartPage = 0;
bool fPropertiesChanged = false;
if (!CryptUIDlgViewCertificate(ref certViewInfo, ref fPropertiesChanged))
{
int error = Marshal.GetLastWin32Error();
MessageBox.Show(error.ToString());
}
}
}
}


I hope this helps.


Regards,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/01/30/crl-gets-cached-after-we-do-an-online-verification-with-x509chain/
Post name: CRL gets cached after we do an Online verification with X509Chain
Original author: Alejandro Campos Magencio
Posting date: 2009-01-30T03:13:00+00:00


Hi all,

When we use X509Chain class to verify if our certificate is notrevoked, we may experience the following behavior:

1)We do an online verification (X509Chain.ChainPolicy.RevocationMode set to X509RevocationMode.Online) on a valid certificate and it works properly: X509Chain.Buildreturns true because the certificate is valid.

2) We clean the CRL cache with the following command: certutil -urlcache CRL delete.

3) Now we do an offline verification (X509Chain.ChainPolicy.RevocationMode set to X509RevocationMode.Offline) in the same process, and it doesn't work as we would expect after reading X509RevocationMode.Offlinedocumentation: X509Chain.Buildstill returns true even if the CRL cache is empty.

4) If we just do an offline verification in a different process after cleaning the cache, the result is what we would expect: X509Chain.Buildreturns false because the CRL cache is empty.

This behavior that we are experiencing is by design. Check the CRL and AIA Caching section in Certificate Revocation and Status Checking

To increase performance, the CryptoAPI caches CRLs and certificates referenced in AIAs. The entries are cached in memory on a per process basis.

According to this, the CRL can be cached in various locations:
- Memory
- Local File System.

With certutil we only clean the local file system cache. If it's cached in memory, we need to restart the process.

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/01/28/how-to-create-a-certificate-request-with-certenroll-javascript/
Post name: How to create a certificate request with CertEnroll (JavaScript)
Original author: Alejandro Campos Magencio
Posting date: 2009-01-28T06:08:00+00:00


Hi all,


The following Javascript sample shows how to use CertEnroll COM component to create a certificate request:

<html>
<head>
<title>Certificate Request test</title>
</head>
<body>
<object id="objCertEnrollClassFactory" classid="clsid:884e2049-217d-11da-b2a4-000e7bbb2b09"></object>
<script language="javascript">

function CreateRequest()
{
document.write("<br>Create Request...");

try {
// Variables
var objCSP = objCertEnrollClassFactory.CreateObject("X509Enrollment.CCspInformation");
var objCSPs = objCertEnrollClassFactory.CreateObject("X509Enrollment.CCspInformations");
var objPrivateKey = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509PrivateKey");
var objRequest = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509CertificateRequestPkcs10")
var objObjectIds = objCertEnrollClassFactory.CreateObject("X509Enrollment.CObjectIds");
var objObjectId = objCertEnrollClassFactory.CreateObject("X509Enrollment.CObjectId");
var objX509ExtensionEnhancedKeyUsage = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509ExtensionEnhancedKeyUsage");
var objExtensionTemplate = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509ExtensionTemplateName")
var objDn = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX500DistinguishedName")
var objEnroll = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509Enrollment")

// Initialize the csp object using the desired Cryptograhic Service Provider (CSP)
objCSP.InitializeFromName("Microsoft Enhanced Cryptographic Provider v1.0");

// Add this CSP object to the CSP collection object
objCSPs.Add(objCSP);

// Provide key container name, key length and key spec to the private key object
//objPrivateKey.ContainerName = "AlejaCMa";
objPrivateKey.Length = 1024;
objPrivateKey.KeySpec = 1; // AT_KEYEXCHANGE = 1

// Provide the CSP collection object (in this case containing only 1 CSP object)
// to the private key object
objPrivateKey.CspInformations = objCSPs;

// Initialize P10 based on private key
objRequest.InitializeFromPrivateKey(1, objPrivateKey, ""); // context user = 1

// 1.3.6.1.5.5.7.3.2 Oid - Extension
objObjectId.InitializeFromValue("1.3.6.1.5.5.7.3.2");
objObjectIds.Add(objObjectId);
objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
objRequest.X509Extensions.Add(objX509ExtensionEnhancedKeyUsage);

// 1.3.6.1.5.5.7.3.3 Oid - Extension
//objExtensionTemplate.InitializeEncode("1.3.6.1.5.5.7.3.3");
//objRequest.X509Extensions.Add(objExtensionTemplate);

// DN related stuff
objDn.Encode("CN=alejacma", 0); // XCN_CERT_NAME_STR_NONE = 0
objRequest.Subject = objDn;

// Enroll
objEnroll.InitializeFromRequest(objRequest);
var pkcs10 = objEnroll.CreateRequest(3); // XCN_CRYPT_STRING_BASE64REQUESTHEADER = 3

document.write("<br>" + pkcs10);
document.write("<br>The end!");
}
catch (ex) {
document.write("<br>" + ex.description);
return false;
}

return true;
}

CreateRequest();

</script>

</body>
</html>


And the following Javascript sample shows how to install the response from the CA (Certificate Authority):

<html>
<head>
<title>Certificate Request test</title>
</head>
<body>
<object id="objCertEnrollClassFactory" classid="clsid:884e2049-217d-11da-b2a4-000e7bbb2b09"></object>
<script language="javascript">

function InstallCert()
{
document.write("<br>Installing certificate...");

try {
// Variables
var objEnroll = objCertEnrollClassFactory.CreateObject("X509Enrollment.CX509Enrollment")
var sPKCS7 = "-----BEGIN CERTIFICATE-----" +
"MIIKFQYJKoZIhvcNAQcCoIIKBjCCCgICAQExADALBgkqhkiG9w0BBwGgggnqMIIF" +
"QjCCBCqgAwIBAgIKYbzdPwAAAAAAVzANBgkqhkiG9w0BAQUFADBJMRMwEQYKCZIm" +
...
"h25CSWewZhpgbZkKPATLzidc0EjrWLl74RU32HEqkl2+R7yAdBQjMQA=" +
"-----END CERTIFICATE-----"

objEnroll.Initialize(1); // ContextUser
objEnroll.InstallResponse(0, sPKCS7, 6, ""); // AllowNone = 0, XCN_CRYPT_STRING_BASE64_ANY = 6
}
catch (ex) {
document.write("<br>" + ex.description);
return false;
}

return true;
}

InstallCert();

</script>

</body>
</html>


Note: this code must be runin the same machine where we made the request.


Note: these samples just create the request and install the response from the CA. If we need to send the request to the CA and get its response programmatically, the following C# sample may help with the objects and methods we can use to achieve this: How to create a certificate request with CertEnroll and .NET (C#).


I hope this helps.


Regards,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/01/23/sha-2-support-on-windows-xp/
Post name: SHA-2 support on Windows XP
Original author: Alejandro Campos Magencio
Posting date: 2009-01-23T08:12:00+00:00


Hi all,

If you try to use any SHA-2 algorithm (SHA-256, SHA-384 and SHA-512) onWindows XP, you may getthe following error when using i.e. CryptCreateHash: NTE_BAD_ALGID or -2146893816 or 0x80090008 or "Invalid algorithm specified". Same algorithms are supported on Vista, though.

Can we use SHA-2 algorithms in Windows XP at all?The answer is yes, but it will depend on the CSP (Cryptographic Service Provider) that we use to perform the cryptographic operations.

According to our documentation, Windows XP SP3 supports all SHA-2 algorithms except SHA-224:

Overview of Windows XP Service Pack 3
"
Implements and supports the SHA2 hashing algorithms (SHA256, SHA384, and SHA512) in X.509 certificate validation. This has been added to the crypto module rsaenh.dll.
"

Our "Microsoft Base/Strong/Enhanced Cryptographic Providers" are implemented on Rsaenh.dll. If you try to use CryptCreateHashwith any SHA-2 Algid (CALG_SHA_256, CALG_SHA_384, CALG_SHA_512)and any of these CSP, you will still get a NTE_BAD_ALGID error on XP SP3. Why? The issue is that those Algid's are only valid with providers of type PROV_RSA_AES, and these CSP are of type PROV_RSA_FULL.

"Microsoft Enhanced RSA and AES Cryptographic Provider" (or "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" as it's called on Windows XP SP3) is implemented in rsaenh.dll and is of type PROV_RSA_AES.

Note that technically speaking, Microsoft AES Cryptographic Provider is just Microsoft Enhanced Cryptographic Provider with support for AES encryption algorithms.

If you open regedit.exe and go to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults, you will be able to see the available Providers in the system ("Microsoft Enhanced Cryptographic Provider v1.0", "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)", etc.) and the Provider Types ("Type 001" which is "RSA Full (Signature and Key Exchange)", "Type 024" which is "RSA Full and AES"). For each Provider you will also see which dll implements (rsaenh.dll, etc.) it and its Provider Type (1, 24, etc.). For each Provider Type you will see the name of the default Provider for that type. On Vista, default Provider for PROV_RSA_AES is "Microsoft Enhanced RSA and AES Cryptographic Provider", and on XP is "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)".

Regarding SHA-224 support, SHA-224 offers less security than SHA-256 but takes the same amount of resources. Also SHA-224 is not generally used by protocols and applications. The NSA's Suite B standards also do not include it. We have no plans to add it on future versions of our CSPs.

Fortunately, Microsoft's CryptoAPI is based on a model which allows us to use anyCSP which implements any algorithm. So we don't and won't implement SHA-224 in our own CSPs, but that doesn't mean that we can't use SHA-224 at all on Windows. We just need a third-party CSP which implements it, or create our own.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)