• [转]通过CSP读取证书


    1. 通过Csp读取证书使用的函数

    CryptGetUserKey

    获取公私钥对的句柄

    注意AT_SIGNATURE,AT_KEYEXCHANGE的不同,前者签名,后者加密。

    CryptGetKeyParam

    读取和公私钥对相关联的证书

    注意使用KP_CERTIFICATE

    2. 指定Csp容器

    通常获取证书时,usbkey已经发证完毕。这是比较难以判断容器的名称。通常会选择默认容器,但有些RA发证时比较特别,可能会使用两个容器。签名证书使用默认容器,而加密证书使用指定的某个容器。

    为了验证上面所说的情况,需要枚举Usbkey上的容器进行选择查看。

    CryptGetProvParam

    注意: 第二个参数使用PP_ENUMCONTAINERS

    获取第一个容器名称的时候,最后的参数使用CRYPT_FIRST

    接下去,调用时使用最后的参数CRYPT_NEXT,当GetLastError的值等于ERROR_NO_MORE_ITEMS则表示没有容器了。

    指定好了容器名称后再进行证书的读取工作,下面列出了程序运行结果:

    签名证书容器

    A crypto context with the MyKeyContainer key container

    has been acquired.

    0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364

    1. ContainName is KOAL_CSP_WRAPPER_CONTAINER

    2. ContainName is J

    The handle has been released.

    Please select a container:

    0

    A crypto context with the 3d06503f-e4ed-4e89-8d56-2960aa5f0364 key container

    has been acquired.

    Encrypt Certification:

    Invalid parameter

    CryptGetKeyParam Failed 0x57

    Sign Certification:

    CertLen is 791

    A new certificate as been created.

    测试 310103198301011234

    SANCA

    The handle has been released.

    加密证书容器

    A crypto context with the MyKeyContainer key container

    has been acquired.

    0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364

    1. ContainName is KOAL_CSP_WRAPPER_CONTAINER

    2. ContainName is J

    The handle has been released.

    Please select a container:

    1

    A crypto context with the KOAL_CSP_WRAPPER_CONTAINER key container

    has been acquired.

    Encrypt Certification:

    CertLen is 759

    A new certificate as been created.

    测试 310103198301011234

    SANCA

    Sign Certification:

    Invalid parameter

    CryptGetKeyParam Failed 0x57

    The handle has been released.

    3. 相关代码

    // getPubKey.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"
    #include <windows.h>
    #include <WinCrypt.h>
    #include <stdio.h>

    #include <vector>
    #include <string>

    using namespace std;

    vector<string> contain_vector;

    //CRYPT_DELETEKEYSET

    int TestEnumContainers(HCRYPTPROV hCryptProv)
    {
    BYTE pbData[1000]; // 1000 will hold the longest
    DWORD cbData = 1000;
    int count = 0;

    if ( CryptGetProvParam(
    hCryptProv,
    PP_ENUMCONTAINERS,
    (BYTE *)&pbData,
    &cbData,
    CRYPT_FIRST))
    {
    pbData[cbData] = '\0';
    printf("%d. ContainName is %s\n", count++, pbData);
    contain_vector.push_back((char *)pbData);

    pbData[0] = '\0';
    cbData = 1000;

    while( CryptGetProvParam(
    hCryptProv,
    PP_ENUMCONTAINERS,
    (BYTE *)&pbData,
    &cbData,
    CRYPT_NEXT)
    )
    {
    if( ERROR_NO_MORE_ITEMS == GetLastError())
    {
    break;
    }

    pbData[cbData] = '\0';
    printf("%d. ContainName is %s\n", count++, pbData);
    contain_vector.push_back((char *)pbData);
    pbData[0] = '\0';
    cbData = 1000;
    }

    }

    return count;
    }

    int EnumContainers()
    {
    //--------------------------------------------------------------------
    // Declare and initialize variables.
    HCRYPTPROV hCryptProv = NULL; // Handle for a cryptographic

    // provider context.
    LPCSTR UserName = "MyKeyContainer"; // Name of the key container
    LPCSTR ProviderName = "eSafe Cryptographic Service Provider v2.0";

    int count = -1;

    // to be used.
    //--------------------------------------------------------------------
    // Attempt to acquire a context and a key
    // container. The context will use the default CSP
    // for the RSA_FULL provider type. DwFlags is set to 0
    // to attempt to open an existing key container.

    if(CryptAcquireContext(
    &hCryptProv, // Handle to the CSP
    NULL, // Container name
    ProviderName, // Use the default provider
    PROV_RSA_FULL, // Provider type
    0)) // Flag values
    {
    printf("A crypto context with the %s key container \n", UserName);
    printf("has been acquired.\n\n");

    count = TestEnumContainers(hCryptProv);

    }
    else
    {
    //--------------------------------------------------------------------
    // An error occurred in acquiring the context. This could mean
    // that the key container requested does not exist. In this case,
    // the function can be called again to attempt to create a new key
    // container. Error codes are defined in winerror.h.
    if (GetLastError() == NTE_BAD_KEYSET)
    {
    if(CryptAcquireContext(
    &hCryptProv,
    NULL,
    ProviderName,
    PROV_RSA_FULL,
    CRYPT_NEWKEYSET))
    {
    printf("A new key container has been created.\n");
    count = TestEnumContainers(hCryptProv);
    }
    else
    {
    printf("Could not create a new key container.\n");
    exit(1);
    }
    }
    else
    {
    printf("A cryptographic service handle could not be acquired.\n");
    exit(1);
    }

    } // End of else

    //--------------------------------------------------------------------
    // A cryptographic context and a key container is available. Perform
    // any functions that require a Cryptographic provider handle.

    //--------------------------------------------------------------------
    // When the handle is no longer needed, it must be released.

    if (CryptReleaseContext(hCryptProv,0))
    {
    printf("The handle has been released.\n");
    }
    else
    {
    printf("The handle could not be released.\n");
    }

    return count;
    }


    void DecodePubKey(HCRYPTPROV hCryptProv, DWORD dwKeySpec)
    {
    HCRYPTKEY hCurKey= 0;
    BOOL ret=TRUE;
    //
    // Check if a key already exisis,
    // If it don't generate a key!
    ///////////////////////////////////////////
    if (!CryptGetUserKey(hCryptProv, dwKeySpec, &hCurKey))
    {
    int error = GetLastError();
    // Make sure error is no key.
    if (error != NTE_NO_KEY)
    {
    printf("First Call to CryptGenKey Failed- with error other than NTE_NO_KEY: [0x%X]\n",error);
    ret=FALSE;
    goto done;
    }
    }

    unsigned char uchCertInfo[2000];
    DWORD CertLen = 2000;
    DWORD error = 0;

    if (!CryptGetKeyParam(hCurKey, KP_CERTIFICATE, uchCertInfo, &CertLen , 0))
    {

    //ERROR_MORE_DATA


    error = GetLastError();

    if( ERROR_INVALID_PARAMETER == error)
    {
    printf("Invalid parameter\n");
    }

    if (error != NTE_BAD_TYPE) {
    // If error is bad_type then we just can't set the property.
    // Likely means our provider isn't a smart card.
    // If there was another error, we should report it.
    printf("CryptGetKeyParam Failed 0x%x\n",error);
    }
    ret=FALSE;
    goto done;
    }

    printf("CertLen is %d\n", CertLen );


    // MAKING X509 CERTIFICATE

    #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
    PCCERT_CONTEXT pCertContext = NULL;

    //------------------------------------------------------------------
    // Create a new certificate from the encoded part of
    // an available certificate. pDesiredCert is a previously
    // assigned PCCERT_CONTEXT variable.
    if(pCertContext = CertCreateCertificateContext(
    MY_ENCODING_TYPE, // The encoding type
    uchCertInfo, // The encoded data from
    // the certificate retrieved
    CertLen)) // The length of the encoded data
    {
    printf("A new certificate as been created.\n");

    // Use the certificate context as needed.
    // ...

    CHAR pszBuff[256];
    CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
    0, NULL, pszBuff, 128);
    printf("%s\n", pszBuff); // 显示名
    CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
    CERT_NAME_ISSUER_FLAG, NULL, pszBuff, 128);
    printf("%s\n", pszBuff); // 颁发者

    // When finished, free the certificate context.
    CertFreeCertificateContext(pCertContext);
    }
    else
    {
    printf("A new certificate could not be created.\n");
    goto done;
    }

    done:
    if (hCurKey) CryptDestroyKey(hCurKey);
    }

    void GetPublicKey(const char *ContainName)
    {
    //--------------------------------------------------------------------
    // Declare and initialize variables.
    HCRYPTPROV hCryptProv = NULL; // Handle for a cryptographic

    // provider context.
    LPCSTR ProviderName = "eSafe Cryptographic Service Provider v2.0";


    // to be used.
    //--------------------------------------------------------------------
    // Attempt to acquire a context and a key
    // container. The context will use the default CSP
    // for the RSA_FULL provider type. DwFlags is set to 0
    // to attempt to open an existing key container.

    if(CryptAcquireContext(
    &hCryptProv, // Handle to the CSP
    ContainName, // Container name
    ProviderName, // Use the default provider
    PROV_RSA_FULL, // Provider type
    0)) // Flag values
    {
    printf("A crypto context with the %s key container \n", ContainName);
    printf("has been acquired.\n\n");


    printf("Encrypt Certification:\n");
    DecodePubKey(hCryptProv, AT_KEYEXCHANGE);

    printf("Sign Certification:\n");
    DecodePubKey(hCryptProv, AT_SIGNATURE);


    }
    else
    {
    //--------------------------------------------------------------------
    // An error occurred in acquiring the context. This could mean
    // that the key container requested does not exist. In this case,
    // the function can be called again to attempt to create a new key
    // container. Error codes are defined in winerror.h.
    if (GetLastError() == NTE_BAD_KEYSET)
    {
    if(CryptAcquireContext(
    &hCryptProv,
    ContainName,
    ProviderName,
    PROV_RSA_FULL,
    CRYPT_NEWKEYSET))
    {
    printf("A new key container has been created.\n");
    }
    else
    {
    printf("Could not create a new key container.\n");
    exit(1);
    }
    }
    else
    {
    printf("A cryptographic service handle could not be acquired.\n");
    exit(1);
    }

    } // End of else

    //--------------------------------------------------------------------
    // A cryptographic context and a key container is available. Perform
    // any functions that require a Cryptographic provider handle.

    //--------------------------------------------------------------------
    // When the handle is no longer needed, it must be released.

    if (CryptReleaseContext(hCryptProv,0))
    {
    printf("The handle has been released.\n");
    }
    else
    {
    printf("The handle could not be released.\n");
    }
    }

    int main(int argc, CHAR* argv[])
    {

    int count = EnumContainers();
    int selectno;


    printf("Please select a container:\n");
    scanf("%d", &selectno);
    if( selectno <= count )
    {
    GetPublicKey(contain_vector[selectno].c_str());
    }

    // 0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364
    // 签名证书

    // 1. ContainName is KOAL_CSP_WRAPPER_CONTAINER
    // 加密证书

    return 0;
    }

  • 相关阅读:
    类(抽象类与非抽象类)和接口
    Arduino学习——u8glib提供的字体样式
    Arduino学习——u8glib库资料整理
    Arduino学习——Arduino main 函数
    全局变量的初始化
    nmake学习笔记2
    Big Endian与Litter Endian
    nmake学习笔记
    重载操作符
    offsetof的意义
  • 原文地址:https://www.cnblogs.com/adylee/p/2320778.html
Copyright © 2020-2023  润新知