Managing Certificates and Certificate Contexts

When you're working with certificates, you usually are actually working with a certificate context. In reality, you are working with a pointer to a certificate context. This normally makes this entire area of functionality a problem for Visual Basic programmers. However, rarely do you need to manipulate anything in the certificate context structure. You therefore can treat the pointer to the context structure as a long variable and just pass this variable value around. Using the pointer this way frees up a lot of certificate functionality so that it can be used with Visual Basic.

Creating a Certificate Context

When you have an encoded certificate, like the certificate retrieved from the Certificate Authority in the preceding chapter, you can convert it directly into a certificate context by using the CertCreateCertificateContext function. This function converts the encoded certificate into a certificate context, allowing you to use the certificate to verify signatures or to encrypt data using the public key enclosed, without storing the certificate in the certificate store. The syntax for this function is as follows:

 Public Declare Function CertCreateCertificateContext Lib "Crypt32.dll" ( _
    ByVal dwCertEncodingType As Long, ByVal pbCertEncoded As String, _
    ByVal cbCertEncoded As Long) As Long

The first parameter (dwCertEncodingType) is a flag that specifies the encoding and formatting used on the certificate. The currently defined encoding types, listed in Table 6.3, are often combined using a binary OR.

Table 6.3. Encoding Type Flag Values
Constant Value Description
X509_ASN_ENCODING &H1 X.509 Encoding
PKCS_7_ASN_ENCODING &H10000 PKCS #7 Message Formatting

The second parameter (pbCertEncoded) is a string containing the encoded certificate. The third parameter (cbCertEncoded) is the size of the certificate string passed in the second parameter.

The return value is a long value that is really a pointer to the certificate context. If the function fails, zero (0) is returned.

Duplicating a Certificate Context

When you need to duplicate a certificate, or in this case a certificate context (by incrementing the reference count), you can use the CertDuplicateCertificateContext function. The syntax for this function is as follows:

 Public Declare Function CertDuplicateCertificateContext _
    Lib "Crypt32.dll" (ByVal pCertContext As Long) As Long

Reference Count

A reference count is where various objects keep track of how many times they are being used. All COM objects do this. One of the reasons for this is so that the object can know when it's safe for it to be unloaded from memory. If an object has a reference count greater than zero, it is still being used and cannot be unloaded.


The one parameter (pCertContext) to this function is the certificate context pointer that you want to duplicate. The return value is a new pointer to the same certificate context.

Finding a Certificate

When you need to find a specific certificate in a certificate store, you can use the CertFindCertificateInStore function. You can use this function repeatedly to find all the certificates that match the search criteria. The syntax for this function is as follows:

 Public Declare Function CertFindCertificateInStore Lib "Crypt32.dll" ( _
    ByVal hCertStore As Long, ByVal dwCertEncodingType As Long, _
    ByVal dwFindFlags As Long, ByVal dwFindType As Long, _
    ByVal pvFindPara As String, ByVal pPrevCertContext As Long) As Long

An alternate declaration for this function is as follows:

 Public Declare Function CertDWFindCertificateInStore Lib "Crypt32.dll" _
    Alias "CertFindCertificateInStore" (ByVal hCertStore As Long, _
    ByVal dwCertEncodingType As Long, ByVal dwFindFlags As Long, _
    ByVal dwFindType As Long, ByRef pvFindPara As Long, _
    ByVal pPrevCertContext As Long) As Long

Tip

You can make a single declaration for this function specifying the fifth parameter (pvFindPara) as the Any data type, passing it by reference. If you do this, you'll need to be careful to pass any strings by value. The declaration for this version are as follows:

   Public Declare Function CertFindCertificateInStore Lib "Crypt32.dll" ( _
       ByVal hCertStore As Long, ByVal dwCertEncodingType As Long, _
       ByVal dwFindFlags As Long, ByVal dwFindType As Long, _
       pvFindPara As Any, ByVal pPrevCertContext As Long) As Long
						


The first parameter (hCertStore) to this function is the handle to the certificate store. This same handle was returned from the CertOpenSystemStore function. The second parameter (dwCertEncodingType) specifies the encoding type of the certificate. These same encoding types were available for the CertCreateCertificateContext function, listed in Table 6.3.

The third parameter (dwFindFlags) is a flag value used to modify how certain searches are performed. The types of searches this value is used with do not lend themselves to use with Visual Basic, so for your purposes, this parameter should always be zero (0).

The fourth parameter (dwFindType) specifies how the find is being performed and what value the find is looking at. The practical (for Visual Basic) values for this parameter are listed in Table 6.4.

Note

The majority of find types require a pointer to a type structure to be passed in for the value to match. Most of these type structures contain pointers to other values that you would need to manipulate to specify the find criteria. As a result, these find types are not easily performed in pure Visual Basic without your dipping into a bit of C/C++ code. You are welcome to try your hand at using them, looking up the type codes and the type structures in the WinCrypt.h C/C++ header file and building your own DLL to perform the pointer manipulation. This approach will not be explored in this book.


Table 6.4. Certificate Find Type Values
Constant Value Description
CERT_FIND_ANY &H0 Returns each certificate in the certificate store
CERT_FIND_EXISTING &HD0000 Finds the certificate that is an exact match for the certificate context passed into this function.
CERT_FIND_ISSUER_OF &HC0000 Finds a certificate that matches the issuer of the certificate context that is passed into this function
CERT_FIND_ISSUER_STR &H70004 Finds a certificate that the issuer name matches the string passed into this function
CERT_FIND_KEY_SPEC &H90000 Finds a certificate having the same key specification as the one passed in to this function
CERT_FIND_PROPERTY &H50000 Finds a certificate with the property specified by the property identifier passed in to this function
CERT_FIND_SUBJECT_STR &H70007 Finds a certificate containing the specified subject name string

The fifth parameter (pvFindPara) to this function is the value to be searched for. For the two string criteria (CERT_FIND_ISSUER_STR and CERT_FIND_SUBJECT_STR), the first version of the function (CertFindCertificateInStore) is used. For the rest, the second version of the func tion (CertDWFindCertificateInStore) is used.

The sixth parameter (pPrevCertContext) is the last certificate context returned by this function. On the first call to this function, this parameter should be zero (0).

The return value from this function is a pointer to a certificate context. As with any other certificate context pointer, this one should be freed using the CertFreeCertificateContext function that you'll be looking at later.

Note

In this and other functions that take the previously returned certificate context pointers, the CertFreeCertificateContext function is automatically called on the previous certificate context pointer that is passed in. This action occurs even if the function is unsuccessful at returning a new certificate context pointer.


Enumerating Certificates

When you need to loop through all the certificates in a particular certificate store, you can use the CertEnumCertificatesInStore function. The syntax for this function is as follows:

 Public Declare Function CertEnumCertificatesInStore Lib "Crypt32.dll" ( _
    ByVal hCertStore As Long, ByVal pPrevCertContext As Long) As Long

The first parameter (hCertStore) to this function is the handle to the certificate store. The second parameter (pPrevCertContext) is the pointer to the previous certificate context returned by this function. The first time this function is called, the second parameter should be zero (0). The return value from this function is a pointer to a new certificate context.

Getting an Issuer Certificate

When you want to retrieve the certificate of the issuer of a certificate from the certificate store, you can use the CertGetIssuerCertificateFromStore function. The syntax for this function is as follows:

 Public Declare Function CertGetIssuerCertificateFromStore _
    Lib "Crypt32.dll" (ByVal hCertStore As Long, _
    ByVal pSubjectContext As Long, ByVal pPrevIssuerContext As Long, _
    ByRef pdwFlags As Long) As Long

The first parameter (hCertStore) to this function is the handle to the certificate store. The second parameter (pSubjectContext) is the pointer to the certificate for which you want to retrieve the issuer certificates.

The third parameter (pPrevIssuerContext) is the pointer to the previous issuer certificate. On the first call to this function, this parameter must be zero (0).

Note

Certificate Authorities can often have multiple certificates, especially when close to the expiration date of one of their certificates.


The fourth parameter (pdwFlags) is a long variable in which a flag value is passed and returned. This flag can be passed through a bitwise AND to determine the various flag values that have been set on return. You can use a bitwise OR to combine values for controlling how the search is performed. The possible values are listed in Table 6.5.

Table 6.5. Certificate Issuer Retrieval Status Flags
Constant Value Description
CERT_STORE_NO_CRL_FLAG &H10000 No matching CRL was found.
CERT_STORE_NO_ISSUER_FLAG &H20000 No issuer certificate was found.
CERT_STORE_REVOCATION_FLAG &H4 Checks to see whether the subject certificate is on the issuer's revocation list.
CERT_STORE_SIGNATURE_FLAG &H1 Checks to see whether the signature of the subject certificate is valid using the issuer's public key.
CERT_STORE_TIME_VALIDITY_FLAG &H2 Checks to see whether the subject certificate's validity period has expired.

For the last three of the flags in Table 6.5, if the verification check is successful, the flag is set to zero (0), so you do need to perform the bitwise check to verify the flag values after the func tion returns.

The return value from this function is a pointer to the certificate context of the issuer certificate. If no certificate is found, the return value is zero (0).

Serializing a Certificate

When you need to be able to store a certificate on a disk or other storage media, possibly even send it to another application, you can serialize the certificate, along with its properties, by using the CertSerializeCertificateStoreElement function. This function places the certificate and its properties into a string variable. The syntax for this function is as follows:

 Public Declare Function CertSerializeCertificateStoreElement _
    Lib "Crypt32.dll" (ByVal pCertContext As Long, _
    ByVal dwFlags As Long, ByVal pbElement As String, _
    pcbElement As Long) As Long

The first parameter (pCertContext) to this function is the pointer to the certificate context. This same long value was returned by the function used to retrieve the certificate from the certificate store. The second parameter (dwFlags) is reserved for future use and must always by zero (0).

The third parameter (pbElement) is the string variable into which the certificate will be placed. This variable must be sized to hold the certificate prior to calling this function. If the NULL string (vbNullString) is passed in this variable, the fourth parameter (pcbElement) will return the size of the string needed to hold the certificate and its properties.

The fourth parameter (pcbElement) is a long variable that specifies the size of the string variable passed in the third parameter. After the function has completed, this variable will contain the actual size of the certificate in the string variable.

You might use this function as follows:

Dim lCertSize As Long
Dim lResult As Long
Dim sCert as String

'--- Null the target string, so we can get the size of the string
'--- that will be exported
lCertSize = 0

'--- Call CertSerializeCertificateStoreElement with the nulled string.
'--- This will give us the required string size that will be needed to
'--- hold the exported key
lResult = CertSerializeCertificateStoreElement (m_lCertContext, 0, _
        vbNullString, lCertSize)

'--- Size the target string for the size specified, filling it with
'--- null characters
sCert = String(lCertSize, vbNullChar)

'--- Serialize the certificate
If Not CBool(CertSerializeCertificateStoreElement (m_lCertContext, 0, _
        sCert, lCertSize)) Then
    '--- Perform error handling
					

Verifying a Certificate

When you need to verify that a certificate is still valid, you can use the CertVerifySubject CertificateContext function. This function checks the aspects of the certificate that you specify, which are the same aspects that can be verified with the CertGetIssuerCertificate FromStore function. The syntax for this function is as follows:

 Public Declare Function CertVerifySubjectCertificateContext _
    Lib "Crypt32.dll" (ByVal pSubject As Long, _
    ByVal pIssuer As Long, pdwFlags As Long) As Long

The first parameter (pSubject) for this function is the pointer to the certificate context of the certificate to be verified. The second parameter (pIssuer) is the pointer to the certificate context of the issuer's certificate. This parameter can be zero (0) if the only aspect being checked is to verify that the certificate isn't past its expiration date.

The third parameter (pdwFlags) is a set of flags that specify which aspects of the certificate to check. These flags can be set using the OR statement and verified using an AND. When the certificate passes one of the checks, that flag is set to zero (0). The available flags are listed in Table 6.6.

Table 6.6. Certificate Verification Status Flags
Constant Value Description
CERT_STORE_REVOCATION_FLAG &H4 Checks to see whether the subject certificate is on the issuer's revocation list
CERT_STORE_SIGNATURE_FLAG &H1 Checks to see whether the signature of the subject certificate is valid using the issuer's public key
CERT_STORE_TIME_VALIDITY_FLAG &H2 Checks to see whether the subject certificate's validity period has expired

Deleting a Certificate

When you want to delete a particular certificate from a certificate store, you can use the CertDeleteCertificateFromStore function. The syntax for this function is as follows:

 Public Declare Function CertDeleteCertificateFromStore _
    Lib "Crypt32.dll" (ByVal pCertContext As Long) As Long

The only parameter (pCertContext) to this function is the pointer to the certificate context.

Note

The CertDeleteCertificateFromStore function deletes the certificate from the cer tificate store and frees the certificate context being pointed at by the parameter passed in. However, if you have duplicate certificate contexts, you still need to free all of them to release the resources being held by the contexts.


Freeing a Certificate Context

After you have finished with a particular certificate context, you need to be sure to release the resources being held by the certificate context by calling the CertFreeCertificateContext function. The syntax for this function is as follows:

 Public Declare Function CertFreeCertificateContext _
    Lib "Crypt32.dll" (ByVal pCertContext As Long) As Long

The only parameter (pCertContext) to this function is the pointer to the certificate context.

Tip

Remember that functions that replace a passed-in context with a new context automatically delete the passed-in context, even if the function call fails. So be sure that you only use the CertFreeCertificateContext function to delete contexts that are still valid.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset