【问题标题】:Visual Studio: Getting all certificate issuer details from executableVisual Studio:从可执行文件中获取所有证书颁发者详细信息
【发布时间】:2021-05-29 04:38:48
【问题描述】:

我希望能够从 Windows 资源管理器中获取所有发行人数据,如下所示:

我已经能够从https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certgetnamestringw 获取 CN,但我不知道那个针对 CN 的调用是什么(如果我这样做了,我也许能够弄清楚如何获取其他所有内容)。我试过用谷歌搜索诸如“api wintrust issuer CommonName Organization”和“wincrypt organization commonname”之类的东西,但这就像API洗掉了所有其他发行人数据一样。

【问题讨论】:

  • @AdrianMole 到目前为止,这就是我得到的全部
  • @AdrianMole ...除非你认为这个人有答案:stackoverflow.com/a/9498520/1676382。他追求的是“主题”,但如果我替换为Issuer,我可能会拥有我所追求的东西
  • @AdrianMole 是的,我试过了,得到了一个以逗号分隔的字段列表。我还是很想知道你是怎么做到的。你能告诉我你用来从 API 获取数据的函数吗,因为直到现在我都无法访问它。
  • 实际上,我的代码只获得了 Windows 对话框中显示的一些项目。但是,它确实分别通过调用CERT_NAME_ISSUER_FLAG0 来获取“Issuer”和“Subject”名称。假设您已经可以获得一个有效的PCERT_CONTEXT 值,我很高兴发布一个从中获取这些值的代码 sn-p。获取序列号也很简单。

标签: c++ visual-studio winapi wincrypt


【解决方案1】:

只需要使用CertNameToStr并设置&(pCertContext->pCertInfo->Issuer)参数即可:

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

我修改了official sample供大家参考:

#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);
} 

【讨论】:

  • 对,好像和stackoverflow.com/a/9498520/1676382很像,只不过是针对发行人的,不是针对主体的。无论如何,我似乎被逗号分隔的 X500 地址所诅咒,我必须解析这些字段。如果 API 可以分离出字段以便我不需要解析,那将是理想的。
  • 所以我没有遇到同样的问题,你能不能编辑问题,显示你需要处理的字段并解释你期望的结果。
  • 您好,这个答案能解决您的问题吗?如果您有任何问题,请随时告诉我,如果有帮助,请接受。
  • 我认为答案是“是”,尽管我没有使用您的示例。但我确实根据stackoverflow.com/a/9498520/1676382的灵感使用了CertNameToStr()
猜你喜欢
  • 2012-07-06
  • 2011-03-24
  • 2011-12-13
  • 2015-08-31
  • 2021-09-16
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
相关资源
最近更新 更多