Certificati, Store e un po' di utilities via CryptoAPI

Oggi ho dovuto riesumare i ricordi sulle CryptoAPI e C SDK. Ecco un po' di codice per la gestione dei certificati X509, i certificate store, i key containers e un po' di utilities che possono risultare utili :-)

Attenzione, se riutilizzate il codice verificate che si integri con il vostro sistema di Exception Management!!

Certificati

/**************************************************************************

* Function: void CSpy_DumpExtraCertInfo(PCCERT_CONTEXT pcert)

*

* Purpose :  Print additional Certificate information

**************************************************************************/

void CSpy_DumpExtraCertInfo(PCCERT_CONTEXT pcert)

{

    TCHAR szName[1000];

    PCCERT_CONTEXT pCurrentCert;

    PCCERT_CONTEXT pIssuerCert;

    DWORD dwVerificationFlags;

    LPWSTR lpszString = (LPWSTR)malloc(sizeof(TCHAR) * MAX_PATH);

   

    SYSTEMTIME stNotBefore,stNotAfter;

    DWORD    dwBitLen;

    DWORD    dwData;

    PBYTE pThumbprint;

    PBYTE pData;

__try{

    _tprintf(L"\n");

    // display leaf name

if(!CertNameToStr(pcert->dwCertEncodingType,

                      &pcert->pCertInfo->Subject,

                      CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,

                      szName, (DWORD)sizeof(TCHAR)*(_tcslen(szName)+1)))

                     

    {

        _tprintf(L"**** Error 0x%x building subject name\n", GetLastError());

    }

    _tprintf(L" subject: %s\n", szName);

   

    if(!CertNameToStr(pcert->dwCertEncodingType,

                      &pcert->pCertInfo->Issuer,

                      CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,

                      szName, (DWORD)sizeof(TCHAR)*(_tcslen(szName)+1)))

    {

        _tprintf(L"**** Error 0x%x building issuer name\n", GetLastError());

    }

    _tprintf(L" issuer: %s\n", szName);

   

    _tprintf(L" serial number: ");

    dwData = pcert->pCertInfo->SerialNumber.cbData;

    for (DWORD n = 0; n < dwData; n++)

    {

        _tprintf(L"%02X",pcert->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]);

        if( n>0&&(1== n % 2))

            _tprintf(L" ");

    }

    _tprintf(L"\n");

    FileTimeToSystemTime(&pcert->pCertInfo->NotBefore, &stNotBefore);

    wsprintf(lpszString, L"%02d/%02d/%d",stNotBefore.wDay, stNotBefore.wMonth, stNotBefore.wYear);

    _tprintf(L" NotBefore : %s\n",lpszString);

    FileTimeToSystemTime(&pcert->pCertInfo->NotAfter, &stNotAfter);

    wsprintf(lpszString, L"%02d/%02d/%d",stNotAfter.wDay, stNotAfter.wMonth, stNotAfter.wYear);

    _tprintf(L" NotAfter : %s\n",lpszString);

 

//Thumbprint

_tprintf(L" Thumbprint : ");

     if (!CertGetCertificateContextProperty(pcert,

                                               CERT_SHA1_HASH_PROP_ID,

                                               NULL,

                                               &dwData))

        {

            _tprintf(L"Error : CertGetCertificateContextProperty() failed in retrieve memory settings.\n");

            return;

        }

    if (NULL == (pThumbprint = (BYTE*) malloc(dwData)))

        {

            _tprintf(L"Error [E_OUTOFMEMORY]: malloc() failed.\n");

            return;

        }

   

    if (!CertGetCertificateContextProperty(pcert,

                                               CERT_SHA1_HASH_PROP_ID,

                                               pThumbprint,

                                               &dwData))

        {

            _tprintf(L"Error : CertGetCertificateContextProperty() failed.\n");

            return;

        }

    for (DWORD n = 0; n < dwData; n++)

    {

        _tprintf(L"%02X",pThumbprint[n]);

        if( n>0&&(1== n % 2))

            _tprintf(L" ");

    }

    _tprintf(L"\n");

    free(pThumbprint);

//UI description

if(CertGetCertificateContextProperty(pcert,

                                               CERT_DESCRIPTION_PROP_ID,

                                               NULL,

                                               &dwData))

    {

        if (NULL == (pData = (BYTE*) malloc(dwData)))

        {

            _tprintf(L"Error [E_OUTOFMEMORY]: malloc() failed.\n");

            return;

        }

        if(CertGetCertificateContextProperty(pcert,

                                               CERT_DESCRIPTION_PROP_ID,

                                               pData,

                                               &dwData))

        {

            _tprintf(L" Description=%s\n",pData);

        }

            free(pData);

    } //end od UI

CSpy_DumpCertificateExtensions(pcert);

//Public Key Infos

_tprintf(L" Public Key :\n");

    if (0 != (dwBitLen = CertGetPublicKeyLength(

                MY_ENCODING_TYPE,

                &pcert->pCertInfo->SubjectPublicKeyInfo)))

            _tprintf(L" length=%i\n", dwBitLen);

    else

_tprintf(L"**** Error 0x%x in CertGetPublicKeyLength\n", GetLastError());

   

            _tprintf(L" Algorithm ID= ");

    //TODO: Add a new function to decode CRYPT_ALGORITHM_IDENTIFIER

int counter=0;

    while(pcert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId[counter] != '\0')

    {

        _tprintf(L"%c",pcert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId[counter++]);       

    }

    _tprintf(L"\n");

   

    _tprintf(L" Key=");

    dwData = pcert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData;

    for (DWORD n = 0; n < dwData; n++)

    {

        _tprintf(L"%02X",pcert->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData[n]);

        if( n>0&&(1== n % 2))

            _tprintf(L" ");

    }

    _tprintf(L"\n");

    //_tprintf(L" Private Key : %s",(CSpy_CertificateHasPrivateKey(pcert))?L"Present":L"Not present");

_tprintf(L" Private Key : ");

    if(CSpy_CertificateHasPrivateKey(pcert))

    {

        _tprintf(L"YES\n");

        CSpy_DumpCSPInfos(pcert);

    }else

{

        _tprintf(L"NO\n");

    }

    // display certificate chain

pCurrentCert = pcert;

    while(pCurrentCert != NULL)

    {

        dwVerificationFlags = 0;

        pIssuerCert = CertGetIssuerCertificateFromStore(pcert->hCertStore,

                                                        pCurrentCert,

                                                        NULL,

                                                        &dwVerificationFlags);

        if(pIssuerCert == NULL)

        {

            if(pCurrentCert != pcert)

            {

                CertFreeCertificateContext(pCurrentCert);

            }

            break;

        }

        if(!CertNameToStr(pIssuerCert->dwCertEncodingType,

                          &pIssuerCert->pCertInfo->Subject,

                          CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,

                          szName, (DWORD)sizeof(TCHAR)*(_tcslen(szName)+1)))

        {

            _tprintf(L"**** Error 0x%x building subject name\n", GetLastError());

        }

        _tprintf(L" CA subject: %s\n", szName);

        if(!CertNameToStr(pIssuerCert->dwCertEncodingType,

                          &pIssuerCert->pCertInfo->Issuer,

                          CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,

                          szName, (DWORD)sizeof(TCHAR)*(_tcslen(szName)+1)))

        {

            _tprintf(L"**** Error 0x%x building issuer name\n", GetLastError());

        }

        _tprintf(L" CA issuer: %s\n\n", szName);

        if(pCurrentCert != pcert)

        {

            CertFreeCertificateContext(pCurrentCert);

        }

        pCurrentCert = pIssuerCert;

        pIssuerCert = NULL;

    }

    } //end__try

__finally

{

       

    }

}

/**************************************************************************
* Function: bool CSpy_CertificateHasPrivateKey(PCCERT_CONTEXT pcert)
*
* Purpose : Test if a certificate has the private key
**************************************************************************/

bool CSpy_CertificateHasPrivateKey(PCCERT_CONTEXT pcert)
{
    DWORD cb = 0;

    return CertGetCertificateContextProperty(pcert,
                                             CERT_KEY_PROV_INFO_PROP_ID,
                                             NULL,
                                             &cb)
                                             !=0; //to avoid Compiler warning (level 3) C4800
}

/**************************************************************************
* Function: UINT CSpy_DumpCertificateExtensions(PCCERT_CONTEXT pCertContext)
*
* Purpose : Display cert extensions. Return number of extensions
**************************************************************************/

UINT CSpy_DumpCertificateExtensions(PCCERT_CONTEXT pCertContext)
{
   
    _tprintf(L" N. Ext. : %d\n",pCertContext->pCertInfo->cExtension);
   
    if (pCertContext->pCertInfo->cExtension>0)
    {
        for(int x =0; x <(int)pCertContext->pCertInfo->cExtension;x++)
        {
            _tprintf(L" Critical=%s ",(pCertContext->pCertInfo->rgExtension->fCritical)? L"Yes":L"NO");
            _tprintf(L" OID=");
            int n=0;
            while(pCertContext->pCertInfo->rgExtension->pszObjId[n]!='\0')
                _tprintf(L"%c",(TCHAR)pCertContext->pCertInfo->rgExtension->pszObjId[n++]);
            _tprintf(L"\n");
               
            pCertContext->pCertInfo->rgExtension++;

        }//endfor(int x =0; x <pCertContext->pCertInfo->cExtension;x++)
    } //endif (pCertContext->pCertInfo->cExtension>0)

    return pCertContext->pCertInfo->cExtension;
}

 

Certificate Store

/**************************************************************************

* Function: void CSpy_DumpStore(TCHAR *storeName)

*

* Purpose : Open a list all certificate in a store

**************************************************************************/

void CSpy_DumpStore(TCHAR *storeName)

{

    HCERTSTORE               hCertStore;

    PCCERT_CONTEXT           pCertContext = NULL;

    DWORD                    dwFlags=0;

    DWORD                    dwStrType = CERT_OID_NAME_STR;

    DWORD                    cbNameLen;

    TCHAR                    *sz;

    long                     nCerts=0;   

   

    if (_tcsclen(storeName) > MAX_PATH )

        storeName[MAX_PATH] = '\0';

    _tprintf(L"\nDumping '%s' Store.....\n",storeName);

    //--------------------------------------------------------------------

// Begin Processing by opening a certificate store.

if(!(hCertStore=CertOpenStore(

        CERT_STORE_PROV_SYSTEM,

        MY_ENCODING_TYPE,

        NULL,

        CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_OPEN_EXISTING_FLAG ,

        storeName)))

    {

        CSpy_DisplayError(L"The store did not open.");

    }

    while(pCertContext = CertEnumCertificatesInStore(

                hCertStore,

                pCertContext))

    {

        //--------------------------------------------------------------------

// Get and display

// the name of subject of the certificate.

if(!(cbNameLen = CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,NULL,0)))

        {

            CSpy_DisplayError(L"CertGetName 1 failed.");

        }

        if(!(sz = (TCHAR*) malloc(sizeof(TCHAR) *cbNameLen+1)))

            CSpy_DisplayError(L"Memory allocation failed.");

       

        if(CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,(LPWSTR)sz,cbNameLen+1))

        {

            _tprintf(L"\nCertificate n. %d Version=V%d :(%s).",nCerts+1,pCertContext->pCertInfo->dwVersion+1,sz);

        }

        else

{

            CSpy_DisplayError(L"CertGetName failed.");

        }

        free(sz);

        CSpy_DumpExtraCertInfo(pCertContext);

       

        nCerts++;

    } // End of while loop

   

    _tprintf(L"\n=>Total : %s store contains %d certificates",storeName,nCerts); 

   

    //--------------------------------------------------------------------

// Close the store.

if(CertCloseStore(hCertStore,CERT_CLOSE_STORE_CHECK_FLAG))

    {

        if(true == g_bverbose)

            _tprintf(L"The store is closed. All certificates are released.\n");

    }

    else

{

        if(true == g_bverbose)

            _tprintf(L"The store was closed, but certificates still in use.\n");

    }

}

  

Key Containers

/**************************************************************************
* Function: DWORD CSpy_DeleteKeyContainer(PCCERT_CONTEXT pCertContext)
*
* Purpose :
**************************************************************************/

DWORD CSpy_DeleteKeyContainer(PCCERT_CONTEXT pCertContext)
{
    DWORD nRetCode = 0;
    DWORD cb = 0;
    CRYPT_KEY_PROV_INFO * pKeyProvInfo = NULL;

    __try
    {
        HCRYPTPROV hCryptProv;

        if (!CryptAcquireContext(&hCryptProv,
                                  pKeyProvInfo->pwszContainerName,
                                  pKeyProvInfo->pwszProvName,
                                  pKeyProvInfo->dwProvType,
                                  CRYPT_DELETEKEYSET))
        {
            CSpy_DisplayError (L"Unable to Delete the context.");
            _tprintf(L" %s ",pKeyProvInfo->pwszContainerName);
            __leave;
        }
    }

    __finally
    {
        if (pKeyProvInfo)
        {
            free(pKeyProvInfo);
        }
    }

    return nRetCode;

}

 

Utilities

/**************************************************************************
* Function: VOID DumpBinaryData( PBYTE pBuffer, ULONG uLen )
*
* Purpose : DumpBinaryData()
**************************************************************************/
VOID CSpy_DumpBinaryData( PBYTE pBuffer, ULONG uLen )
{
    TCHAR  *p = (TCHAR *)pBuffer;
    TCHAR     c;
    DWORD    dw;
    UINT     i = 0;
   
    _tprintf(L"{\n ");
    while( i < uLen ) {
        c = *p;
        dw = (DWORD)(c);
        _tprintf(L"0x%02X, ", dw & 0xFF );
        i++;
        p++;
        if ((i % 8) == 0)
            _tprintf(L"\n " );
    }
    _tprintf(L"\n}\n" );
}

 

--Mario