Exemplo n.º 1
0
WCHAR const *
ceGetOIDNameA(
    IN char const *pszObjId)
{
    CRYPT_OID_INFO const *pInfo = NULL;
    WCHAR const *pwszName = L"";

    // First try looking up the ObjectId as an Extension or Attribute, because
    // we get a better Display Name, especially for Subject RDNs: CN, L, etc.
    // If that fails, look it up withoput restricting the group.

    pInfo = CryptFindOIDInfo(
			CRYPT_OID_INFO_OID_KEY,
			(VOID *) pszObjId,
			CRYPT_EXT_OR_ATTR_OID_GROUP_ID);

    if (NULL == pInfo || NULL == pInfo->pwszName || L'\0' == pInfo->pwszName[0])
    {
	pInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (VOID *) pszObjId, 0);
    }
    if (NULL != pInfo && NULL != pInfo->pwszName && L'\0' != pInfo->pwszName[0])
    {
	pwszName = pInfo->pwszName;
    }
    return(pwszName);
}
Exemplo n.º 2
0
Arquivo: oid.c Projeto: austin987/wine
static void test_findOIDInfo(void)
{
    static WCHAR sha1[] = { 's','h','a','1',0 };
    static CHAR oid_rsa_md5[] = szOID_RSA_MD5;
    ALG_ID alg = CALG_SHA1;
    ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN };
    PCCRYPT_OID_INFO info;

    info = CryptFindOIDInfo(0, NULL, 0);
    ok(info == NULL, "Expected NULL\n");
    info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid_rsa_md5, 0);
    ok(info != NULL, "Expected to find szOID_RSA_MD5\n");
    if (info)
    {
        ok(!strcmp(info->pszOID, szOID_RSA_MD5), "Expected %s, got %s\n",
         szOID_RSA_MD5, info->pszOID);
        ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n",
           U(*info).Algid);
    }
    info = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, sha1, 0);
    ok(info != NULL, "Expected to find sha1\n");
    if (info)
    {
        ok(!strcmp(info->pszOID, szOID_OIWSEC_sha1), "Expected %s, got %s\n",
         szOID_OIWSEC_sha1, info->pszOID);
        ok(U(*info).Algid == CALG_SHA1, "Expected CALG_SHA1, got %d\n",
           U(*info).Algid);
    }
    info = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY, &alg, 0);
    ok(info != NULL, "Expected to find sha1\n");
    if (info)
    {
        ok(!strcmp(info->pszOID, szOID_OIWSEC_sha1), "Expected %s, got %s\n",
         szOID_OIWSEC_sha1, info->pszOID);
        ok(U(*info).Algid == CALG_SHA1, "Expected CALG_SHA1, got %d\n",
           U(*info).Algid);
    }
    info = CryptFindOIDInfo(CRYPT_OID_INFO_SIGN_KEY, algs, 0);
    ok(info != NULL, "Expected to find md5RSA\n");
    if (info)
    {
        ok(!strcmp(info->pszOID, szOID_RSA_MD5RSA), "Expected %s, got %s\n",
         szOID_RSA_MD5RSA, info->pszOID);
        ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n",
           U(*info).Algid);
    }
}
Exemplo n.º 3
0
Arquivo: oid.c Projeto: Jactry/wine
static void test_registerOIDInfo(void)
{
    static const WCHAR winetestW[] = { 'w','i','n','e','t','e','s','t',0 };
    static char test_oid[] = "1.2.3.4.5.6.7.8.9.10";
    CRYPT_OID_INFO info1;
    const CRYPT_OID_INFO *info2;
    HKEY key;
    DWORD ret, size, type, value;
    char buf[256];

    SetLastError(0xdeadbeef);
    ret = CryptUnregisterOIDInfo(NULL);
    ok(!ret, "should fail\n");
    ok(GetLastError() == E_INVALIDARG, "got %#x\n", GetLastError());

    memset(&info1, 0, sizeof(info1));
    SetLastError(0xdeadbeef);
    ret = CryptUnregisterOIDInfo(&info1);
    ok(!ret, "should fail\n");
    ok(GetLastError() == E_INVALIDARG, "got %#x\n", GetLastError());

    info1.cbSize = sizeof(info1);
    SetLastError(0xdeadbeef);
    ret = CryptUnregisterOIDInfo(&info1);
    ok(!ret, "should fail\n");
    ok(GetLastError() == E_INVALIDARG, "got %#x\n", GetLastError());

    info1.pszOID = test_oid;
    SetLastError(0xdeadbeef);
    ret = CryptUnregisterOIDInfo(&info1);
    ok(!ret, "should fail\n");
    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got %u\n", GetLastError());

    info2 = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (void *)test_oid, 0);
    ok(!info2, "should fail\n");

    SetLastError(0xdeadbeef);
    /* While it succeeds, the next call does not write anything to the
     * registry on Windows because dwGroupId == 0.
     */
    ret = CryptRegisterOIDInfo(&info1, 0);
    ok(ret, "got %u\n", GetLastError());

    ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key);
    ok(ret == ERROR_FILE_NOT_FOUND, "got %u\n", ret);

    info2 = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (void *)test_oid, 0);
    ok(!info2, "should fail\n");

    info1.pwszName = winetestW;
    info1.dwGroupId = CRYPT_HASH_ALG_OID_GROUP_ID;
    SetLastError(0xdeadbeef);
    ret = CryptRegisterOIDInfo(&info1, CRYPT_INSTALL_OID_INFO_BEFORE_FLAG);
    if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
    {
        skip("Need admin rights\n");
        return;
    }
    ok(ret, "got %u\n", GetLastError());

    /* It looks like crypt32 reads the OID info from registry only on load,
     * and CryptFindOIDInfo will find the registered OID on next run
     */
    info2 = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, (void *)test_oid, 0);
    ok(!info2, "should fail\n");

    ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key);
    ok(!ret, "got %u\n", ret);

    memset(buf, 0, sizeof(buf));
    size = sizeof(buf);
    ret = RegQueryValueExA(key, "Name", NULL, &type, (BYTE *)buf, &size);
    ok(!ret, "got %u\n", ret);
    ok(type == REG_SZ, "got %u\n", type);
    ok(!strcmp(buf, "winetest"), "got %s\n", buf);

    value = 0xdeadbeef;
    size = sizeof(value);
    ret = RegQueryValueExA(key, "Flags", NULL, &type, (BYTE *)&value, &size);
    ok(!ret, "got %u\n", ret);
    ok(type == REG_DWORD, "got %u\n", type);
    ok(value == 1, "got %u\n", value);

    RegCloseKey(key);

    CryptUnregisterOIDInfo(&info1);

    ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key);
    ok(ret == ERROR_FILE_NOT_FOUND, "got %u\n", ret);
}
Exemplo n.º 4
0
Arquivo: oid.c Projeto: Jactry/wine
static void test_findOIDInfo(void)
{
    static WCHAR sha256ECDSA[] = { 's','h','a','2','5','6','E','C','D','S','A',0 };
    static WCHAR sha1[] = { 's','h','a','1',0 };
    static CHAR oid_rsa_md5[] = szOID_RSA_MD5, oid_sha256[] = szOID_NIST_sha256;
    static CHAR oid_ecdsa_sha256[] = szOID_ECDSA_SHA256;
    ALG_ID alg = CALG_SHA1;
    ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN };
    const struct oid_info
    {
        DWORD key_type;
        void *key;
        const char *oid;
        ALG_ID algid;
        ALG_ID broken_algid;
    } oid_test_info [] =
    {
        { CRYPT_OID_INFO_OID_KEY, oid_rsa_md5, szOID_RSA_MD5, CALG_MD5 },
        { CRYPT_OID_INFO_NAME_KEY, sha1, szOID_OIWSEC_sha1, CALG_SHA1 },
        { CRYPT_OID_INFO_ALGID_KEY, &alg, szOID_OIWSEC_sha1, CALG_SHA1 },
        { CRYPT_OID_INFO_SIGN_KEY, algs, szOID_RSA_MD5RSA, CALG_MD5 },
        { CRYPT_OID_INFO_OID_KEY, oid_sha256, szOID_NIST_sha256, CALG_SHA_256, -1 },
    };
    PCCRYPT_OID_INFO info;
    int i;

    info = CryptFindOIDInfo(0, NULL, 0);
    ok(info == NULL, "Expected NULL\n");

    for (i = 0; i < ARRAY_SIZE(oid_test_info); i++)
    {
        const struct oid_info *test = &oid_test_info[i];

        info = CryptFindOIDInfo(test->key_type, test->key, 0);
        ok(info != NULL, "Failed to find %s.\n", test->oid);
        if (info)
        {
            ok(!strcmp(info->pszOID, test->oid), "Unexpected OID %s, expected %s\n", info->pszOID, test->oid);
            ok(U(*info).Algid == test->algid || broken(U(*info).Algid == test->broken_algid),
                "Unexpected Algid %d, expected %d\n", U(*info).Algid, test->algid);
        }
    }

    info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid_ecdsa_sha256, 0);
    if (info)
    {
        DWORD *data;

        ok(info->cbSize == sizeof(*info), "Unexpected structure size %d.\n", info->cbSize);
        ok(!strcmp(info->pszOID, oid_ecdsa_sha256), "Expected %s, got %s\n", oid_ecdsa_sha256, info->pszOID);
        ok(!lstrcmpW(info->pwszName, sha256ECDSA), "Expected %s, got %s\n",
            wine_dbgstr_w(sha256ECDSA), wine_dbgstr_w(info->pwszName));
        ok(info->dwGroupId == CRYPT_SIGN_ALG_OID_GROUP_ID,
           "Expected CRYPT_SIGN_ALG_OID_GROUP_ID, got %u\n", info->dwGroupId);
        ok(U(*info).Algid == CALG_OID_INFO_CNG_ONLY,
           "Expected CALG_OID_INFO_CNG_ONLY, got %d\n", U(*info).Algid);

        data = (DWORD *)info->ExtraInfo.pbData;
        ok(info->ExtraInfo.cbData == 8, "Expected 8, got %d\n", info->ExtraInfo.cbData);
        ok(data[0] == CALG_OID_INFO_PARAMETERS, "Expected CALG_OID_INFO_PARAMETERS, got %x\n", data[0]);
        ok(data[1] == CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG,
            "Expected CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG, got %x\n", data[1]);

        ok(!lstrcmpW(info->pwszCNGAlgid, BCRYPT_SHA256_ALGORITHM), "Expected %s, got %s\n",
           wine_dbgstr_w(BCRYPT_SHA256_ALGORITHM), wine_dbgstr_w(info->pwszCNGAlgid));
        ok(!lstrcmpW(info->pwszCNGExtraAlgid, CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), "Expected %s, got %s\n",
           wine_dbgstr_w(CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), wine_dbgstr_w(info->pwszCNGExtraAlgid));
    }
    else
        win_skip("Host does not support ECDSA_SHA256, skipping test\n");
}
Exemplo n.º 5
0
BOOL WINAPI CertStrToNameW(DWORD dwCertEncodingType, LPCWSTR pszX500,
 DWORD dwStrType, void *pvReserved, BYTE *pbEncoded, DWORD *pcbEncoded,
 LPCWSTR *ppszError)
{
    CERT_NAME_INFO info = { 0, NULL };
    LPCWSTR str;
    struct KeynameKeeper keeper;
    DWORD i, error = ERROR_SUCCESS;
    BOOL ret = TRUE;

    TRACE("(%08lx, %s, %08lx, %p, %p, %p, %p)\n", dwCertEncodingType,
     debugstr_w(pszX500), dwStrType, pvReserved, pbEncoded, pcbEncoded,
     ppszError);

    CRYPT_InitializeKeynameKeeper(&keeper);
    str = pszX500;
    while (str && *str && !error && ret)
    {
        struct X500TokenW token;

        error = CRYPT_GetNextKeyW(str, &token, ppszError);
        if (!error && token.start)
        {
            PCCRYPT_OID_INFO keyOID;

            CRYPT_KeynameKeeperFromTokenW(&keeper, &token);
            keyOID = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, keeper.keyName,
             CRYPT_RDN_ATTR_OID_GROUP_ID);
            if (!keyOID)
            {
                if (ppszError)
                    *ppszError = token.start;
                error = CRYPT_E_INVALID_X500_STRING;
            }
            else
            {
                str = token.end;
                while (isspace(*str))
                    str++;
                if (*str != '=')
                {
                    if (ppszError)
                        *ppszError = str;
                    error = CRYPT_E_INVALID_X500_STRING;
                }
                else
                {
                    static const WCHAR commaSep[] = { ',',0 };
                    static const WCHAR semiSep[] = { ';',0 };
                    static const WCHAR crlfSep[] = { '\r','\n',0 };
                    static const WCHAR allSeps[] = { ',',';','\r','\n',0 };
                    LPCWSTR sep;

                    str++;
                    if (dwStrType & CERT_NAME_STR_COMMA_FLAG)
                        sep = commaSep;
                    else if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
                        sep = semiSep;
                    else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
                        sep = crlfSep;
                    else
                        sep = allSeps;
                    error = CRYPT_GetNextValueW(str, dwStrType, sep, &token,
                     ppszError);
                    if (!error)
                    {
                        str = token.end;
                        ret = CRYPT_ValueToRDN(dwCertEncodingType, &info,
                         keyOID, &token, ppszError);
                    }
                }
            }
        }
    }
    CRYPT_FreeKeynameKeeper(&keeper);
    if (!error)
    {
        ret = CryptEncodeObjectEx(dwCertEncodingType, X509_NAME, &info,
         0, NULL, pbEncoded, pcbEncoded);
        for (i = 0; i < info.cRDN; i++)
        {
            DWORD j;

            for (j = 0; j < info.rgRDN[i].cRDNAttr; j++)
                LocalFree(info.rgRDN[i].rgRDNAttr[j].Value.pbData);
            CryptMemFree(info.rgRDN[i].rgRDNAttr);
        }
        CryptMemFree(info.rgRDN);
    }
    else
    {
        SetLastError(error);
        ret = FALSE;
    }
    return ret;
}
Exemplo n.º 6
0
DWORD WINAPI CertNameToStrW(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
 DWORD dwStrType, LPWSTR psz, DWORD csz)
{
    static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
     CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
    static const WCHAR commaSep[] = { ',',' ',0 };
    static const WCHAR semiSep[] = { ';',' ',0 };
    static const WCHAR crlfSep[] = { '\r','\n',0 };
    static const WCHAR plusSep[] = { ' ','+',' ',0 };
    static const WCHAR spaceSep[] = { ' ',0 };
    DWORD ret = 0, bytes = 0;
    BOOL bRet;
    CERT_NAME_INFO *info;

    TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
     psz, csz);
    if (dwStrType & unsupportedFlags)
        FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);

    bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
     pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
    if (bRet)
    {
        DWORD i, j, sepLen, rdnSepLen;
        LPCWSTR sep, rdnSep;

        if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
            sep = semiSep;
        else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
            sep = crlfSep;
        else
            sep = commaSep;
        sepLen = lstrlenW(sep);
        if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
            rdnSep = spaceSep;
        else
            rdnSep = plusSep;
        rdnSepLen = lstrlenW(rdnSep);
        for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
        {
            for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
            {
                DWORD chars;
                LPCSTR prefixA = NULL;
                LPCWSTR prefixW = NULL;

                if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
                    prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
                else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
                {
                    PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
                     CRYPT_OID_INFO_OID_KEY,
                     info->rgRDN[i].rgRDNAttr[j].pszObjId,
                     CRYPT_RDN_ATTR_OID_GROUP_ID);

                    if (oidInfo)
                        prefixW = oidInfo->pwszName;
                    else
                        prefixA = info->rgRDN[i].rgRDNAttr[j].pszObjId;
                }
                if (prefixW)
                {
                    /* - 1 is needed to account for the NULL terminator. */
                    chars = CRYPT_AddPrefixW(prefixW,
                     psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
                    ret += chars;
                    csz -= chars;
                }
                else if (prefixA)
                {
                    /* - 1 is needed to account for the NULL terminator. */
                    chars = CRYPT_AddPrefixAToW(prefixA,
                     psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
                    ret += chars;
                    csz -= chars;
                }
                /* FIXME: handle quoting */
                chars = CertRDNValueToStrW(
                 info->rgRDN[i].rgRDNAttr[j].dwValueType, 
                 &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
                 psz ? csz - ret : 0);
                if (chars)
                    ret += chars - 1;
                if (j < info->rgRDN[i].cRDNAttr - 1)
                {
                    if (psz && ret < csz - rdnSepLen - 1)
                        memcpy(psz + ret, rdnSep, rdnSepLen * sizeof(WCHAR));
                    ret += rdnSepLen;
                }
            }
            if (i < info->cRDN - 1)
            {
                if (psz && ret < csz - sepLen - 1)
                    memcpy(psz + ret, sep, sepLen * sizeof(WCHAR));
                ret += sepLen;
            }
        }
        LocalFree(info);
    }
    if (psz && csz)
    {
        *(psz + ret) = '\0';
        csz--;
        ret++;
    }
    else
        ret++;
    TRACE("Returning %s\n", debugstr_w(psz));
    return ret;
}
Exemplo n.º 7
0
DWORD WINAPI CertNameToStrA(DWORD dwCertEncodingType, PCERT_NAME_BLOB pName,
 DWORD dwStrType, LPSTR psz, DWORD csz)
{
    static const DWORD unsupportedFlags = CERT_NAME_STR_NO_QUOTING_FLAG |
     CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
    static const char commaSep[] = ", ";
    static const char semiSep[] = "; ";
    static const char crlfSep[] = "\r\n";
    static const char plusSep[] = " + ";
    static const char spaceSep[] = " ";
    DWORD ret = 0, bytes = 0;
    BOOL bRet;
    CERT_NAME_INFO *info;

    TRACE("(%ld, %p, %08lx, %p, %ld)\n", dwCertEncodingType, pName, dwStrType,
     psz, csz);
    if (dwStrType & unsupportedFlags)
        FIXME("unsupported flags: %08lx\n", dwStrType & unsupportedFlags);

    bRet = CryptDecodeObjectEx(dwCertEncodingType, X509_NAME, pName->pbData,
     pName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &bytes);
    if (bRet)
    {
        DWORD i, j, sepLen, rdnSepLen;
        LPCSTR sep, rdnSep;

        if (dwStrType & CERT_NAME_STR_SEMICOLON_FLAG)
            sep = semiSep;
        else if (dwStrType & CERT_NAME_STR_CRLF_FLAG)
            sep = crlfSep;
        else
            sep = commaSep;
        sepLen = strlen(sep);
        if (dwStrType & CERT_NAME_STR_NO_PLUS_FLAG)
            rdnSep = spaceSep;
        else
            rdnSep = plusSep;
        rdnSepLen = strlen(rdnSep);
        for (i = 0; (!psz || ret < csz) && i < info->cRDN; i++)
        {
            for (j = 0; (!psz || ret < csz) && j < info->rgRDN[i].cRDNAttr; j++)
            {
                DWORD chars;
                char prefixBuf[10]; /* big enough for GivenName */
                LPCSTR prefix = NULL;

                if ((dwStrType & 0x000000ff) == CERT_OID_NAME_STR)
                    prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
                else if ((dwStrType & 0x000000ff) == CERT_X500_NAME_STR)
                {
                    PCCRYPT_OID_INFO oidInfo = CryptFindOIDInfo(
                     CRYPT_OID_INFO_OID_KEY,
                     info->rgRDN[i].rgRDNAttr[j].pszObjId,
                     CRYPT_RDN_ATTR_OID_GROUP_ID);

                    if (oidInfo)
                    {
                        WideCharToMultiByte(CP_ACP, 0, oidInfo->pwszName, -1,
                         prefixBuf, sizeof(prefixBuf), NULL, NULL);
                        prefix = prefixBuf;
                    }
                    else
                        prefix = info->rgRDN[i].rgRDNAttr[j].pszObjId;
                }
                if (prefix)
                {
                    /* - 1 is needed to account for the NULL terminator. */
                    chars = CRYPT_AddPrefixA(prefix,
                     psz ? psz + ret : NULL, psz ? csz - ret - 1 : 0);
                    ret += chars;
                    csz -= chars;
                }
                /* FIXME: handle quoting */
                chars = CertRDNValueToStrA(
                 info->rgRDN[i].rgRDNAttr[j].dwValueType, 
                 &info->rgRDN[i].rgRDNAttr[j].Value, psz ? psz + ret : NULL,
                 psz ? csz - ret : 0);
                if (chars)
                    ret += chars - 1;
                if (j < info->rgRDN[i].cRDNAttr - 1)
                {
                    if (psz && ret < csz - rdnSepLen - 1)
                        memcpy(psz + ret, rdnSep, rdnSepLen);
                    ret += rdnSepLen;
                }
            }
            if (i < info->cRDN - 1)
            {
                if (psz && ret < csz - sepLen - 1)
                    memcpy(psz + ret, sep, sepLen);
                ret += sepLen;
            }
        }
        LocalFree(info);
    }
    if (psz && csz)
    {
        *(psz + ret) = '\0';
        csz--;
        ret++;
    }
    else
        ret++;
    TRACE("Returning %s\n", debugstr_a(psz));
    return ret;
}
Exemplo n.º 8
0
/*****************************************************************************
 HrSign

    Creates XML signature
*****************************************************************************/
HRESULT
HrSign(
    LPCWSTR         wszFileOut,
    const SIGN_PARA *pPara,
    ULONG           argc,
    LPWSTR          argv[]
    )
{
    HCRYPTXML               hSig = NULL;
    HCRYPTXML               hRef = NULL;
    HRESULT                 hr = S_FALSE;
    ULONG                   i;

    const CRYPT_XML_ALGORITHM_INFO* pAlgInfo = NULL;

    PCCERT_CHAIN_CONTEXT    pChainContext = NULL;
    HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = NULL; // No release
    DWORD                   dwKeySpec = 0;
    PCCERT_CONTEXT          pCert = NULL;   // No release
    CRYPT_XML_STATUS    Status = {0};

    ULONG               cTransform = 0;
    CRYPT_XML_ALGORITHM *pTransform = NULL;

    const CRYPT_XML_REFERENCE *pRef = NULL;
    CRYPT_XML_DATA_PROVIDER DataProvider = {0};

    CRYPT_XML_PROPERTY  Properties[] = {
        {
            //
            // This property is required for Enveloped or Enveloping signatures
            //
            CRYPT_XML_PROPERTY_SIGNATURE_LOCATION,
            NULL,
            sizeof(LPCWSTR)
        },
    };
    ULONG   cProperties = 0;

    CRYPT_XML_BLOB   Encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };

    CRYPT_XML_ALGORITHM xmlAlg_CanonicalizationMethod = {
                                sizeof( CRYPT_XML_ALGORITHM ),
                                (LPWSTR)pPara->wszCanonicalizationMethod,
                                CRYPT_XML_CHARSET_AUTO,
                                0,
                                NULL
                                };

    CRYPT_XML_ALGORITHM xmlAlg_SignatureMethod = {
                                sizeof( CRYPT_XML_ALGORITHM ),
                                NULL,
                                CRYPT_XML_CHARSET_AUTO,
                                0,
                                NULL
                                };

    CRYPT_XML_ALGORITHM xmlAlg_DigestMethod = {
                                sizeof( CRYPT_XML_ALGORITHM ),
                                NULL,
                                CRYPT_XML_CHARSET_AUTO,
                                0,
                                NULL
                                };

    CRYPT_XML_ALGORITHM xmlAlg_Enveloped = {
                                sizeof( CRYPT_XML_ALGORITHM ),
                                wszURI_XMLNS_TRANSFORM_ENVELOPED,
                                CRYPT_XML_CHARSET_AUTO,
                                0,
                                NULL
                                };
    
    HANDLE  hFile = INVALID_HANDLE_VALUE;

    //
    // Create the output file.
    // This handle will be used by HrWriteXmlToFileCallback and must be closed
    // at the exit.
    //

    hFile = CreateFile(
                                        wszFileOut,
                                        GENERIC_WRITE,
                                        0,
                                        NULL,
                                        CREATE_ALWAYS,
                                        FILE_ATTRIBUTE_NORMAL,
                                        NULL
                                        );

    if( INVALID_HANDLE_VALUE == hFile )
    {
        hr = HRESULT_FROM_WIN32( GetLastError() );
        wprintf( L"ERROR: Unable to create file: '%s'.\r\n", wszFileOut );

        goto CleanUp;
    }

    //
    // Find the signing certificate
    //

    hr = HrGetSignerKeyAndChain(
                                        pPara->wszSubject,
                                        &pChainContext,
                                        &hCryptProvOrNCryptKey,    
                                        &dwKeySpec
                                        );
    if( FAILED(hr) )
    {
        wprintf( L"ERROR: 0x%08x - Unable to get signing certificate.\r\n", hr );
        goto CleanUp;
    }

    //
    // Determine the Digest Method
    //

    {
        pAlgInfo = CryptXmlFindAlgorithmInfo(
                                        CRYPT_XML_ALGORITHM_INFO_FIND_BY_CNG_ALGID,
                                        pPara->wszHashAlgName,
                                        CRYPT_XML_GROUP_ID_HASH,
                                        0
                                        );
        if( NULL == pAlgInfo )
        {
            hr = CRYPT_XML_E_ALGORITHM;
            goto CleanUp;
        }

        xmlAlg_DigestMethod.wszAlgorithm = pAlgInfo->wszAlgorithmURI;
    }

    //
    // Determine the Signature Method
    //
    
    pCert = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
    {
        PCCRYPT_OID_INFO pOIDInfo = NULL;
        LPCWSTR pwszCNGAlgid[2] = {0};

        //
        // First, find the Public Key algorithm name
        //

        pOIDInfo = CryptFindOIDInfo(
                                            CRYPT_OID_INFO_OID_KEY,
                                            pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId,
                                            CRYPT_PUBKEY_ALG_OID_GROUP_ID
                                            );

        if( NULL == pOIDInfo || NULL == pOIDInfo->pwszCNGAlgid )
        {
            hr = CRYPT_XML_E_ALGORITHM;
            goto CleanUp;
        }

        //
        // Second, find XML DigSig URI that corresponds to 
        // combined HASH and  Public Key algorithm names.
        //

        pwszCNGAlgid[0] = pPara->wszHashAlgName;
        pwszCNGAlgid[1] = pOIDInfo->pwszCNGAlgid;

        pAlgInfo = CryptXmlFindAlgorithmInfo(
                                            CRYPT_XML_ALGORITHM_INFO_FIND_BY_CNG_SIGN_ALGID,
                                            pwszCNGAlgid,
                                            CRYPT_XML_GROUP_ID_SIGN,
                                            0
                                            );
        if( NULL == pAlgInfo )
        {
            hr = CRYPT_XML_E_ALGORITHM;
            goto CleanUp;
        }
        xmlAlg_SignatureMethod.wszAlgorithm = pAlgInfo->wszAlgorithmURI;
    }

    //
    // Load input XML file. This must be provided for Enveloped or Enveloping signature
    //

    if( NULL != pPara->wszFileIn )
    {
        hr = HrLoadFile(
                                            pPara->wszFileIn,
                                            &Encoded.pbData,
                                            &Encoded.cbData
                                            );
        if( FAILED(hr) )
        {
            goto CleanUp;
        }
    }

    //
    // Create the document context
    //

    if( NULL != pPara->wszSignatureLocation && 0 != *pPara->wszSignatureLocation )
    {
        // The <Signature> element will be added into this location
        Properties[0].pvValue = &pPara->wszSignatureLocation;
        cProperties++;
    }

    hr = CryptXmlOpenToEncode(
                                            NULL,                   // No custom transforms
                                            0,
                                            pPara->wszSignatureId,
                                            Properties,
                                            cProperties,
                                            (Encoded.cbData > 0 ) ? &Encoded : NULL,
                                            &hSig
                                            );
    if( FAILED(hr) )
    {
        goto CleanUp;
    }

    //
    // Create references
    //

    for( i=0; i<argc; i++ )
    {
        DWORD       dwReferenceFlags = 0;
        LPCWSTR     wsRefId = NULL;
        LPCWSTR     wsUri = NULL;

        if( L'#' != *argv[i] )
        {
            wprintf( L"ERROR: Invalid reference: %s.\r\n", argv[i] );
            hr = E_INVALIDARG;
            goto CleanUp;
        }

        wsUri = argv[i];
        
        if( 0 == wsUri[1] && 1==argc )
        {
            //
            // Special case for Enveloped
            // The URI must be ""
            //
            
            wsUri = L"";
            cTransform = 1;
            pTransform = &xmlAlg_Enveloped;
        }
        else
        if( i+1 < argc )
        {
            //
            // Check if external file is specified
            //

            if( L'#' != *argv[i+1] )
            {
                i++;
                wsRefId = wsUri+1;
                wsUri = argv[i];
            }

            cTransform = 0;
            pTransform = NULL;
        }

        hr = CryptXmlCreateReference(
                                        hSig,               // Parent
                                        dwReferenceFlags,   // Flags
                                        wsRefId,
                                        wsUri,
                                        NULL,
                                        &xmlAlg_DigestMethod,
                                        cTransform,   	
                                        pTransform,
                                        &hRef
                                        );
        if( FAILED(hr) )
        {
            goto CleanUp;
        }

        hr = CryptXmlGetStatus( hRef, &Status );
        if( FAILED(hr) )
        {
            goto CleanUp;
        }

        if( 0 != ( Status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED ))
        {
            //
            // Resolve the external references only.
            // The internal references will be resolved by CryptXml during CryptXmlSign
            //

            if( 0 == ( Status.dwInfoStatus & CRYPT_XML_STATUS_INTERNAL_REFERENCE ))
            {
                hr = CryptXmlGetReference(  hRef, &pRef );
                if( FAILED(hr) )
                {
                    goto CleanUp;
                }

                hr = HrSampleResolveExternalXmlReference(
                                        pRef->wszUri,
                                        &DataProvider
                                        );
                if( FAILED(hr) )
                {
                    goto CleanUp;
                }

                if( NULL == DataProvider.pfnRead )
                {
                    //
                    // Unable to open file for reading
                    //

                    hr = CRYPT_XML_E_UNRESOLVED_REFERENCE;
                    goto CleanUp;
                }

                //
                // Digest the reference
                //

                hr = CryptXmlDigestReference(
                                                hRef,
                                                0,
                                                &DataProvider
                                                );
                if( FAILED(hr) )
                {
                    goto CleanUp;
                }

                //
                // Provider must be released by the callee, which is CryptXmlDigestReference
                //
                ZeroMemory( &DataProvider, sizeof DataProvider );
            }
        }
    }

    {
        //
        // Sign 
        //
        DWORD   dwSignFlags = 0;
        CRYPT_XML_KEYINFO_PARAM KeyInfoParam = {0};
        CERT_BLOB               rgCertificate[8] = {0};
        DWORD c;

        //
        // Include the chain up to the Root
        //
        for( c=0; c<pChainContext->rgpChain[0]->cElement-1 && c<ARRAYSIZE(rgCertificate); c++ )
        {
            rgCertificate[c].pbData = pChainContext->rgpChain[0]->rgpElement[c]->pCertContext->pbCertEncoded;
            rgCertificate[c].cbData = pChainContext->rgpChain[0]->rgpElement[c]->pCertContext->cbCertEncoded;
        }

        KeyInfoParam.cCertificate = c;
        KeyInfoParam.rgCertificate = rgCertificate;

        KeyInfoParam.wszId = pPara->wszKeyInfoId;

        if( pPara->fKV )
        {
            dwSignFlags |= CRYPT_XML_SIGN_ADD_KEYVALUE;
        }

        hr = CryptXmlSign(
                                        hSig,
                                        hCryptProvOrNCryptKey,
                                        dwKeySpec,
                                        dwSignFlags,
                                        CRYPT_XML_KEYINFO_SPEC_PARAM,
                                        &KeyInfoParam,
                                        &xmlAlg_SignatureMethod,
                                        &xmlAlg_CanonicalizationMethod
                                        );
        if( FAILED(hr) )
        {
            wprintf( L"FAIL: 0x%08x CryptXmlSign\r\n", hr );
            goto CleanUp;
        }
        wprintf( L"Successfully signed and created signature.\r\n" );
    }

    {
        //
        // Encode the Signature to file
        //

        static BOOL fTRUE = TRUE;
        CRYPT_XML_PROPERTY rgEncodeProperty[] = {
            {
                //
                // This property is used to produce the declaration at the top of XML.
                //   <?xml version="1.0" encoding="utf-8" standalone="yes"?>
                //
                CRYPT_XML_PROPERTY_DOC_DECLARATION,
                &fTRUE,
                sizeof(fTRUE)
            },
        };

        hr = CryptXmlEncode(
                                        hSig,
                                        CRYPT_XML_CHARSET_UTF8,
                                        rgEncodeProperty,
                                        ARRAYSIZE(rgEncodeProperty),
                                        hFile,
                                        HrWriteXmlToFileCallback
                                        );
        if( FAILED(hr) )
        {
            goto CleanUp;
        }

        wprintf( L"Successfully encoded signature to '%s'.\r\n", wszFileOut );
    }
CleanUp:

    if( INVALID_HANDLE_VALUE != hFile )
    {
        CloseHandle( hFile );
    }

    if( NULL != Encoded.pbData )
    {
        LocalFree( Encoded.pbData );
    }

    if( NULL != pChainContext )
    {
        CertFreeCertificateChain(pChainContext);
    }

    if( NULL != hSig )
    {
        CryptXmlClose( hSig );
    }

    return hr;
}
Exemplo n.º 9
0
/*****************************************************************************
 wmain

*****************************************************************************/
DWORD
__cdecl
wmain(
    int     argc,
    LPWSTR  argv[]
    )
{
    HRESULT                     hr = S_OK;

    BOOL                        fSign = TRUE;        

    LPCWSTR                     pwszInputFile = NULL;
    LPCWSTR                     pwszOutputFile = NULL;

    BYTE                        *pbInput = NULL;
    DWORD                       cbInput = 0;    
    BYTE                        *pbOutput = NULL;
    DWORD                       cbOutput = 0;

    CERT_CHAIN_PARA             ChainPara         = {0};
    CERT_CHAIN_POLICY_PARA      ChainPolicy       = {0};
    CERT_CHAIN_POLICY_STATUS    PolicyStatus      = {0};
    PCCERT_CHAIN_CONTEXT        pChain = NULL;

    PCCERT_CONTEXT              pSignerCert = NULL;
    HCERTSTORE                  hStoreHandle = NULL;

    LPCWSTR                     pwszStoreName = L"MY";  // by default
    LPCWSTR                     pwszCName = L"Test";    // by default

    LPCWSTR                     wszHashAlgName = L"SHA1";

    int                         i;

    //
    // options
    //

    for( i=1; i<argc; i++ )
    {
        if ( lstrcmpW (argv[i], L"/?") == 0 ||
             lstrcmpW (argv[i], L"-?") == 0 ) 
        {
            Usage( L"cms_sign.exe" );
            goto CleanUp;
        }

        if( *argv[i] != L'-' )
            break;

        if ( lstrcmpW (argv[i], L"-s") == 0 )
        {
            if( i+1 >= argc )
            {
                hr = E_INVALIDARG;
                goto CleanUp;
            }

            pwszStoreName = argv[++i];
        }
        else
        if ( lstrcmpW (argv[i], L"-n") == 0 )
        {
            if( i+1 >= argc )
            {
                hr = E_INVALIDARG;
                goto CleanUp;
            }

            pwszCName = argv[++i];
        }
        else
        if ( lstrcmpW (argv[i], L"-a") == 0 )
        {
            if( i+1 >= argc )
            {
                hr = E_INVALIDARG;
                goto CleanUp;
            }

            wszHashAlgName = argv[++i];
        }
    }

    if( 0 == lstrcmpW (argv[i], L"SIGN"))
    {
        if( i+2 >= argc )
        {
            hr = E_INVALIDARG;
            goto CleanUp;
        }

        fSign = TRUE;
        pwszInputFile = argv[++i];
        pwszOutputFile = argv[++i];
    }
    else
    if( 0 == lstrcmpW (argv[i], L"VERIFY"))
    {
        if( i+1 >= argc )
        {
            hr = E_INVALIDARG;
            goto CleanUp;
        }

        fSign = FALSE;
        pwszInputFile = argv[++i];
    }
    else
    {
        hr = E_INVALIDARG;
        goto CleanUp;
    }

    if( i != argc-1 )
    {
        hr = E_INVALIDARG;
        goto CleanUp;
    }

    //-------------------------------------------------------------------
    // Open the certificate store to be searched.

    hStoreHandle = CertOpenStore(
                           CERT_STORE_PROV_SYSTEM,          // the store provider type
                           0,                               // the encoding type is not needed
                           NULL,                            // use the default HCRYPTPROV
                           CERT_SYSTEM_STORE_CURRENT_USER,  // set the store location in a 
                                                            //  registry location
                           pwszStoreName
                           );                               // the store name 

    if( NULL == hStoreHandle )
    {
        hr = HRESULT_FROM_WIN32( GetLastError() );
        goto CleanUp;
    }

    //
    // Load file
    // 

    hr = HrLoadFile(
                                            pwszInputFile,
                                            &pbInput,
                                            &cbInput
                                            );
    if( FAILED(hr) )
    {
        wprintf( L"Unable to read file: %s\n", pwszInputFile );
        goto CleanUp;
    }


    if( fSign )
    {
        //-------------------------------------------------------------------
        // Sign Message

        PCCRYPT_OID_INFO pOidInfo = NULL;
        CRYPT_SIGN_MESSAGE_PARA  SigParams = {0};

        // Create the MessageArray and the MessageSizeArray.
        const BYTE* MessageArray[] = {pbInput};
        DWORD MessageSizeArray[] = {cbInput};

        //
        // Get a certificate that has the specified Subject Name
        //

        pSignerCert = CertFindCertificateInStore(
                               hStoreHandle,
                               X509_ASN_ENCODING ,        // Use X509_ASN_ENCODING
                               0,                         // No dwFlags needed
                               CERT_FIND_SUBJECT_STR,     // Find a certificate with a
                                                          //  subject that matches the 
                                                          //  string in the next parameter
                               pwszCName,                 // The Unicode string to be found
                                                          //  in a certificate's subject
                               NULL);                     // NULL for the first call to the
                                                          //  function; In all subsequent
                                                          //  calls, it is the last pointer
                                                          //  returned by the function
        if( NULL == pSignerCert )
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        //
        // Build a chain in order to include certs to the message
        //

        if( !CertGetCertificateChain(
                                    NULL,                  // use the default chain engine
                                    pSignerCert,           // pointer to the end certificate
                                    NULL,                  // use the default time
                                    NULL,                  // search no additional stores
                                    &ChainPara,            // use AND logic and enhanced key usage 
                                                           //  as indicated in the ChainPara 
                                                           //  data structure
                                    CERT_CHAIN_REVOCATION_CHECK_END_CERT,
                                    NULL,                  // currently reserved
                                    &pChain ))             // return a pointer to the chain created
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        //
        // Verify that the chain complies with Base policy
        //

        ChainPolicy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
        ChainPolicy.dwFlags = 0;

        PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);

        ChainPolicy.pvExtraPolicyPara = NULL;
        if (!CertVerifyCertificateChainPolicy(
                                        CERT_CHAIN_POLICY_BASE,
                                        pChain,
                                        &ChainPolicy,
                                        &PolicyStatus))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        if( PolicyStatus.dwError != S_OK ) 
        {
            ReportError( L"Base Policy Chain Status Failure:", PolicyStatus.dwError  );
            hr = PolicyStatus.dwError;
        }

        // Initialize the signature structure.
        SigParams.cbSize = sizeof(SigParams);
        SigParams.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
        SigParams.pSigningCert = pSignerCert;
        SigParams.cAuthAttr = 0;
        SigParams.dwInnerContentType = 0;
        SigParams.cMsgCrl = 0;
        SigParams.cUnauthAttr = 0;
        SigParams.dwFlags = 0;
        SigParams.pvHashAuxInfo = NULL;
        SigParams.rgAuthAttr = NULL;

        //
        // Addd max of 8 certs to the message
        //

        PCCERT_CONTEXT   rgpMsgCert[8] = {NULL};
        SigParams.rgpMsgCert = rgpMsgCert;
        for( SigParams.cMsgCert=0; SigParams.cMsgCert<pChain->rgpChain[0]->cElement && SigParams.cMsgCert<8; SigParams.cMsgCert++ )
        {
            rgpMsgCert[SigParams.cMsgCert] = pChain->rgpChain[0]->rgpElement[SigParams.cMsgCert]->pCertContext;
        }

        //
        // Find OID
        //

        pOidInfo = CryptFindOIDInfo(
                                    CRYPT_OID_INFO_NAME_KEY,
                                    (void*)wszHashAlgName,
                                    CRYPT_HASH_ALG_OID_GROUP_ID
                                    );

        if( NULL == pOidInfo )
        {
            hr = CRYPT_E_UNKNOWN_ALGO;
            goto CleanUp;
        }

        SigParams.HashAlgorithm.pszObjId = (LPSTR)pOidInfo->pszOID;


        // First, get the size of the signed BLOB.
        if( !CryptSignMessage(
                                &SigParams,
                                FALSE,
                                1,
                                MessageArray,
                                &cbInput,
                                NULL,
                                &cbOutput ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        // Allocate memory for the signed BLOB.
        pbOutput = (BYTE*)LocalAlloc( LPTR, cbOutput );
        if( NULL == pbOutput )
        {
            hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
            goto CleanUp;
        }

        // Get the signed message BLOB.
        if( !CryptSignMessage(
                                &SigParams,
                                FALSE,
                                1,
                                MessageArray,
                                MessageSizeArray,
                                pbOutput,
                                &cbOutput ))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        hr = HrSaveFile(
                                    pwszOutputFile,
                                    pbOutput,
                                    cbOutput
                                    );
        if( FAILED(hr) )
        {
            wprintf( L"Unable to save file: %s\n", pwszOutputFile );
            goto CleanUp;
        }

        wprintf( L"Successfully signed message using CryptSignMessage.\n");
    }
    else
    {
        //-------------------------------------------------------------------
        // Verify signed message

        CRYPT_VERIFY_MESSAGE_PARA   VerifyParams = {0};

        VerifyParams.cbSize = sizeof(VerifyParams);
        VerifyParams.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
        VerifyParams.hCryptProv = 0;
        VerifyParams.pfnGetSignerCertificate = NULL;
        VerifyParams.pvGetArg = NULL;

        // First, call CryptVerifyMessageSignature to get the length 
        // of the buffer needed to hold the decoded message.
        if( !CryptVerifyMessageSignature(
                                        &VerifyParams,
                                        0,
                                        pbInput,
                                        cbInput,
                                        NULL,
                                        &cbOutput,
                                        NULL))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        pbOutput = (BYTE*)LocalAlloc( LPTR, cbOutput );
        if( NULL == pbOutput )
        {
            hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
            goto CleanUp;
        }

        //---------------------------------------------------------------
        // Call CryptVerifyMessageSignature again to verify the signature
        // and, if successful, copy the decoded message into the buffer. 
        if( !CryptVerifyMessageSignature(
                                        &VerifyParams,
                                        0,
                                        pbInput,
                                        cbInput,
                                        pbOutput,
                                        &cbOutput,
                                        &pSignerCert))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        wprintf( L"Successfully verified signed message using CryptVerifyMessageSignature.\n");

        //
        // Build a chain in order to verify certificate trust
        //

        //
        // Instruction :   Create a certificate store from the CMS message and provide as a parameter to 
        //                 CertGetCertificateChain. This will ensure that all additional certificates from
		//                 the CMS message are used in chain building
        //                 Otherwise chain will be build using the local stores only.
        // 

        if( !CertGetCertificateChain(
                                    NULL,                  // use the default chain engine
                                    pSignerCert,           // pointer to the end certificate
                                    NULL,                  // use the default time
                                    NULL,                  // search no additional stores
                                    &ChainPara,            // use AND logic and enhanced key usage 
                                                           //  as indicated in the ChainPara 
                                                           //  data structure
                                    CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
                                    NULL,                  // currently reserved
                                    &pChain ))             // return a pointer to the chain created
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        //
        // Verify that the chain complies with Base policy
        //

        ChainPolicy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
        ChainPolicy.dwFlags = 0;

        PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);

        ChainPolicy.pvExtraPolicyPara = NULL;
        if (!CertVerifyCertificateChainPolicy(
                                        CERT_CHAIN_POLICY_BASE,
                                        pChain,
                                        &ChainPolicy,
                                        &PolicyStatus))
        {
            hr = HRESULT_FROM_WIN32( GetLastError() );
            goto CleanUp;
        }

        if( PolicyStatus.dwError != S_OK ) 
        {
            ReportError( L"Base Policy Chain Status Failure:", PolicyStatus.dwError  );
            hr = PolicyStatus.dwError;
        }
    }

    hr = S_OK;

    //-------------------------------------------------------------------
    // Clean up memory.

CleanUp:

    if( NULL != pbInput )
    {
        LocalFree(pbInput);
    }

    if( NULL != pbOutput )
    {
        LocalFree(pbOutput);
    }

    if( NULL != pChain )
    {
        CertFreeCertificateChain(pChain);
    }

    if( NULL != pSignerCert )
    {
        CertFreeCertificateContext(pSignerCert);
    }

    if( NULL != hStoreHandle)
    {
        CertCloseStore( hStoreHandle, 0 );
    }

    if( FAILED( hr ))
    {
        ReportError( NULL, hr  );
    }

    return (DWORD)hr;
} // End of main