The Engagement

Hi, I am Richard Lewis and I am back from executing a CryptoApi project for an enterprise customer. The client, had this requirement of having to encrypt data between two machines. Sounds meager? Now consider this - The encrypting box was a low end machine with limited resources and had very stringent performance requirements. No managed code could be used on this machine, only pure Win32. The decrypting machine did not understand anything but raw cryptographic bytes. No CMS, no PKCS, no nothing. Crypto API was being used to provide the cryptographic services on the encrypting machine. The decryption machine did not understand CryptoAPI high-level message formats, leaving me with the low-level Crypto API calls. I also had to come out with recommendations for identifying the issuer certificate, using the distinguished name as a means of identifying a digital certificate, performing digital certificate validity checks and using key material from PKCS#12 for decryption of data. Phew!

The Learnings
a) Extracting public key information from a certificate and importing it into the provider

The steps to do this are:

a)     Retrieve information contained in the subject key identifier extended property of the digital certificate. The CertGetCertificateContextProperty Crypto API function should be used for this.

b)    Import the public key information into the cryptographic service provider (CSP). The CryptImportPublicKeyInfoEx Crypto API function should be used for this.

The subject key identifier property should be present in the digital certificate. This is not often found to be the case; however, its absence should be catered for in code.

b) Identifying the issuer certificate

There are three system stores in which to look for the issuer certificate viz. the personal store (MY store), the CA store and the trusted ROOT store. The CertFindCertificateInStore Crypto API function can be used to search for a certificate in the system stores; in this case we can use the CERT_FIND_ISSUER_OF flag can be used when searching for the issuer’s certificate. An alternate function CertGetCertificateChain could be used instead as it builds a certificate chain context starting from an end certificate and going back, if possible, to a trusted root certificate.

c) Using the distinguished name to identify a digital certificate in the store.

The distinguished name consists of composite relative distinguished names such as common name, organizational unit, organization, country information and the like.

In order to identify a digital certificate having these fields, the CertIsRDNAttrsInCertificateName Crypto API function should be used.

In order to use this function, populate the elements of the CERT_RDN_ATTR array with RDN types corresponding to those that are the criteria for identification.

d) Performing X.509-related validation checks on a digital certificate.

In order to validate a digital certificate the following steps must be performed:

a)     Check if the certificate to be validated contains within it the identity externally provided by the system.

b)    Build the certificate chain right u p to the trusted ROOT certificate. As path of the chain building, validate the time and signature on the certificate. This can be done by using the CertGetCertificateChain. Code for this is provided in “Creating a Certificate Chain” code example article in MSDN.

After the chain has been built, validate the end-user certificate for usage restrictions on that certificate. For example, a digital certificate may not be allowed for data encryption. In such cases the validation logic must cater to these circumstances. The CERT_KEY_USAGE_RESTRICTION_INFO structure is to be used with the CertFindExtension Crypto API function.

e) Obtaining a private key from a PKCS#12 object

 A PKCS#12 file contains digital certificates and private keys. The private keys, if any, can be protected by a password. In order to access the private key in the PKCS#12 a password should be provided.

The PFXImportCertStore Crypto API function should be used to Qextract the certificate store from a PKCS#12 formatted packet.

In order to identify certificates in the PKCS#12 packet that have a corresponding private key, the CertGetCertificateContextProperty with the CERT_KEY_PROV_INFO_PROP_ID flag should be called on each certificate in the PKCS#12 packet.

After the certificate and the corresponding private key have been identified, the CryptAcquireCertificatePrivateKey Crypto API function is used to acquire a provider handle to the digital certificate and the corresponding private key.

The password used to protect the PKCS#12 files should be securely handled in the program.

The certificate context of the certificate corresponding to the private key should be destroyed as soon as possible.

MSDN Ammo

  1. http://www.microsoft.com/mind/0697/crypto.asp
  2. Working with certificate stores http://msdn2.microsoft.com/en-us/library/aa388211.aspx
  3. Encrypting and decrypting data http://msdn2.microsoft.com/en-us/library/aa382016.aspx

Richard Lewis
Security Technologist
ACE Services
richard dot lewis at microsoft dot com