0

I want to be able to get all the issuer data that you can get from Windows Explorer like here: Screen cap of the data I want

I've been able to get CN from https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certgetnamestringw, but I don't know what it is about that call that targets the CN (if I did, I might be able to figure how to get everything else). I've tried Googling things like "api wintrust issuer CommonName Organization" and "wincrypt organization commonname" but it's like the API washes its hands of all the other issuer data.

Barrnet Chou
  • 1,738
  • 1
  • 4
  • 7
Opux
  • 702
  • 1
  • 10
  • 30
  • @AdrianMole so far it's all I got – Opux Feb 26 '21 at 20:26
  • @AdrianMole ...unless you think this guy has the answer: https://stackoverflow.com/a/9498520/1676382. He's going after "subject" but if I substitute `Issuer`, I might have what I'm after – Opux Feb 26 '21 at 20:39
  • @AdrianMole Yes, I tried that and got a comma-delimited list of fields. I'd still be interested to know how you pulled it off. Could you just tell me the functions you used to get the data from the API, because it's been inaccessible to me until now. – Opux Feb 27 '21 at 19:04
  • Actually, my code only gets a few of the items shown in the Windows dialog. However, it *does* get the "Issuer" and "Subject" names by using calls with the `CERT_NAME_ISSUER_FLAG` and `0`, respectively. Assuming you can already get a valid `PCERT_CONTEXT` value, I'm happy to post a code snippet that gets those from that. Getting the serial number is also quite straightforward. – Adrian Mole Feb 27 '21 at 19:25

1 Answers1

1

You only need to use CertNameToStr and set the &(pCertContext->pCertInfo->Issuer) parameter:

CertNameToStr(
            pCertContext->dwCertEncodingType,
            &(pCertContext->pCertInfo->Issuer),
            CERT_X500_NAME_STR,
            pszString,
            cbSize);

I modified the official sample for your reference:

#pragma comment(lib, "crypt32.lib")
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Wincrypt.h>

#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MY_STRING_TYPE (CERT_OID_NAME_STR)
void MyHandleError(LPTSTR);

void main(void)
{
    HCERTSTORE hCertStore;
    PCCERT_CONTEXT pCertContext;
    if (!(hCertStore = CertOpenStore(
        CERT_STORE_PROV_SYSTEM,
        MY_ENCODING_TYPE,
        NULL,
        CERT_SYSTEM_STORE_CURRENT_USER,
        L"MY")))
    {
        MyHandleError(TEXT("The MY system store did not open."));
    }
    pCertContext = NULL;
    while (pCertContext = CertEnumCertificatesInStore(
        hCertStore,
        pCertContext))
    {
        LPTSTR pszString;
        LPTSTR pszName;
        DWORD cbSize;
        CERT_BLOB blobEncodedName;
        if (!(cbSize = CertGetNameString(
            pCertContext,
            CERT_NAME_SIMPLE_DISPLAY_TYPE,
            0,
            NULL,
            NULL,
            0)))
        {
            MyHandleError(TEXT("CertGetName 1 failed."));
        }

        if (!(pszName = (LPTSTR)malloc(cbSize * sizeof(TCHAR))))
        {
            MyHandleError(TEXT("Memory allocation failed."));
        }

        if (CertGetNameString(
            pCertContext,
            CERT_NAME_SIMPLE_DISPLAY_TYPE,
            0,
            NULL,
            pszName,
            cbSize))

        {
            _tprintf(TEXT("\nSubject -> %s.\n"), pszName);
            free(pszName);
        }
        else
        {
            MyHandleError(TEXT("CertGetName failed."));
        }
        if (!(cbSize = CertGetNameString(
            pCertContext,
            CERT_NAME_SIMPLE_DISPLAY_TYPE,
            CERT_NAME_ISSUER_FLAG,
            NULL,
            NULL,
            0)))
        {
            MyHandleError(TEXT("CertGetName 1 failed."));
        }

        if (!(pszName = (LPTSTR)malloc(cbSize * sizeof(TCHAR))))
        {
            MyHandleError(TEXT("Memory allocation failed."));
        }

        if (CertGetNameString(
            pCertContext,
            CERT_NAME_SIMPLE_DISPLAY_TYPE,
            CERT_NAME_ISSUER_FLAG,
            NULL,
            pszName,
            cbSize))
        {
            _tprintf(TEXT("Issuer  -> %s.\n"), pszName);
            free(pszName);
        }
        else
        {
            MyHandleError(TEXT("CertGetName failed."));
        }
        cbSize = CertNameToStr(
            pCertContext->dwCertEncodingType,
            &(pCertContext->pCertInfo->Subject),
            MY_STRING_TYPE,
            NULL,
            0);
        if (1 == cbSize)
        {
            MyHandleError(TEXT("Subject name is an empty string."));
        }
        if (!(pszString = (LPTSTR)malloc(cbSize * sizeof(TCHAR))))
        {
            MyHandleError(TEXT("Memory allocation failed."));
        }
        cbSize = CertNameToStr(
            pCertContext->dwCertEncodingType,
            &(pCertContext->pCertInfo->Issuer),
            CERT_X500_NAME_STR,
            pszString,
            cbSize);
        if (1 == cbSize)
        {
            MyHandleError(TEXT("Issuer name is an empty string."));
        }
        else
        {
            printf("Issuer String = %ls\n", pszString); //what you want
        }

        if (!(CertStrToName(
            MY_ENCODING_TYPE,
            pszString,
            MY_STRING_TYPE,
            NULL,
            NULL,        // NULL to get the number of bytes 
                            // needed for the buffer.          
            &cbSize,     // Pointer to a DWORD to hold the 
                            // number of bytes needed for the 
                            // buffer
            NULL)))     // Optional address of a pointer to
                            // old the location for an error in the 
                            // input string.
        {
            MyHandleError(
                TEXT("Could not get the length of the BLOB."));
        }
        if (!(blobEncodedName.pbData = (LPBYTE)malloc(cbSize)))
        {
            MyHandleError(
                TEXT("Memory Allocation for the BLOB failed."));
        }
        blobEncodedName.cbData = cbSize;

        if (CertStrToName(
            MY_ENCODING_TYPE,
            pszString,
            MY_STRING_TYPE,
            NULL,
            blobEncodedName.pbData,
            &blobEncodedName.cbData,
            NULL))
        {
            _tprintf(TEXT("CertStrToName created the BLOB.\n"));
        }
        else
        {
            MyHandleError(TEXT("Could not create the BLOB."));
        }
        free(blobEncodedName.pbData);
        free(pszString);
    }

    _tprintf(
        TEXT("\nThere are no more certificates in the store. \n"));
    if (CertCloseStore(
        hCertStore,
        CERT_CLOSE_STORE_CHECK_FLAG))
    {
        _tprintf(TEXT("The store is closed. ")
            TEXT("All certificates are released.\n"));
    }
    else
    {
        _tprintf(TEXT("The store was closed, ")
            TEXT("but certificates still in use.\n"));
    }
    _tprintf(TEXT("This demonstration program ran to completion ")
        TEXT("without error.\n"));
} 

void MyHandleError(LPTSTR psz)
{
    _ftprintf(stderr,
        TEXT("An error occurred in running the program. \n"));
    _ftprintf(stderr, TEXT("%s\n"), psz);
    _ftprintf(stderr, TEXT("Error number %x.\n"), GetLastError());
    _ftprintf(stderr, TEXT("Program terminating. \n"));
    exit(1);
} 
Zeus
  • 3,703
  • 3
  • 7
  • 20
  • Right, which seems to be similar to https://stackoverflow.com/a/9498520/1676382, only it's for the issuer not the subject. In any case, it seems I'm cursed w/a comma-separated X500 address, the fields for which I'll have to parse out. If the API could separate out the fields so I don't need to parse, that would be ideal. – Opux Mar 02 '21 at 14:26
  • So I didn't encounter the same problem, can you edit the question to show the fields you need to deal with and explain the results you expect. – Zeus Mar 03 '21 at 00:48
  • Hi, does the answer solve your issue? Please feel free to let me know if you have any issue and also accept it if it does help. – Zeus Mar 05 '21 at 08:41
  • I think the answer is 'yes', although I didn't use your sample. But I did use `CertNameToStr()` based on inspiration from https://stackoverflow.com/a/9498520/1676382 – Opux Mar 05 '21 at 14:37