CryptBinaryToStringA未在B64编码

时间:2018-01-26 19:52:59

标签: c++ windows encoding x509 cryptoapi

我的目标是使用CryptoAPI获取CryptoAPI中生成的签名和编码证书的一些字节,并将它们转换为B64。问题是,正在修复证书标题,但输出不是B64!

我的输出:

  

----- BEGIN CERTIFICATE ----- MIIDfjCCAmagAwIBAgIBAjANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xEDAOBgNVBAoMB0FVVE9TT0wxDzANBgNVBAsMBkNNREVQVDEUMBIGA1UEAwwLbmFtZWRwaXBlQ0EwHhcNMTgwMTI2MTk0NDQ2WhcNMTkwMTI2MTk0NDQ2WjBlMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xDDAKBgNVBAoMA0RpczEmMCQGA1UEAwwdU1ZSLkNNMDA0MDlEOTg4RTk1LjE1MTY5OTQ5OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD28NOZkuJbUsU0COQFrJgMgzGaj / afj6lYKZyTr5oXtenSmTAXN0WJE7Wd7DCfKqPpbnui4mb62Tgn3NCyMyEHY5jzFUWaUIchlmVzkamQzkmE3g99Fhj3EZP9zAEQE7qs7p5aKcgzIHuMRDB16Ap7 / GcFLTUBXcval17yOyU + J9csiywTRA54IK8nvtXzYVvgDSKXOh02VEU9RIjE4C069PKGg04lwZNHm8KvuPJn70PXQQnDaoSkbyvh46lKGhJUsNzNsV0Dpk1owrV9jCCUhpOKdA61Ye8P1oFgLkyu8VV4FjJL7 / t7AwaV7AgV7fVtOQ1fZ1HU4VheDD + Q23snAgMBAAGjNjA0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA4GA1UdDwEB / wQEAwIFoDANBgNVHQoEBjAEAwIGQDANBgkqhkiG9w0BAQsFAAOCAQEAShaqwVJvEjg9n4Tw24hBvl5pXpRGlUjgOQHDsk9sf8WWlDQWZzdRbaw9Y2QBEPuBbxbnF / voiUwYIhWrIYZziZDmx4mHuM1tt7Dyo79pAaJ6KrYkEz OoLP9VCuC1qHsux9cwYb1WiJmJtIZi22aFvAXDCQ3cDr6ej + PbgrXOL + oaS3b95F2ds6zWhDjyFwBLldkAXB4P / GiiOnS3X85DVxWLzY + y88hoKqBYJq5vaAIdLHlqA6jZJYuR2VUjVixggLclAeGUYO9ljLcyS9aer0DFJvdCMKJyUfcN6t6s / tDsKO7nrJrPNIVxbXfg8KzVnWG3Px9KTF9u9bt2G3kJNg == ----- END   CERTIFICATE -----

如果我在此处粘贴上述文字并尝试解码,则会失败...它不是B64: https://www.base64decode.org/

如果我转到https://www.base64encode.org/并粘贴上面的内容,该工具会将其转换为B64,我可以通过我需要进行的内部API调用提交它,OpenSSL对此感到满意。我需要在代码示例中使用最后两个函数调用来执行此操作,但它不起作用。没有错误被抛出。

代码:

std::string sCertificate;
HCRYPTPROV hCaProv = NULL;
PCRYPT_KEY_PROV_INFO pKeyInfo_CA = NULL;
CERT_INFO serverCertInfo;
CRYPT_ALGORITHM_IDENTIFIER signAlgo;
DWORD cbEncodedCert_SERVER = 0;
LPBYTE pbEncodedCert_SERVER = NULL;
DWORD dwB64CertificateLength;
LPSTR lpstrServerCertificate = NULL;

//...
//do a million things to process a CSR and make a certificate ready to be signed

//use CryptSignAndEncodeCertificate to figure out how much space to allocate for the certificate
if (!CryptSignAndEncodeCertificate(
    hCaProv,
    pKeyInfo_CA->dwKeySpec,
    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
    X509_CERT_TO_BE_SIGNED,
    (void*)&serverCertInfo,
    &signAlgo,
    NULL,
    NULL,
    &cbEncodedCert_SERVER
))
{
    LocalFree(pbEnhancedUsage);
    LocalFree(pbUsage);
    LocalFree(pbEncodedBasicConstraints);
    CertFreeCertificateContext(pCACertContext);
    CryptReleaseContext(hCaProv, 0);
    CertCloseStore(hStoreRoot, 0);
    throw std::runtime_error("Unable to sign and encode certificate");
}

//allocate space for the certificate
pbEncodedCert_SERVER = (LPBYTE)LocalAlloc(0, cbEncodedCert_SERVER);

//use CryptSignAndEncodeCertificate to sign and encode the new certificate
if (!CryptSignAndEncodeCertificate(
    hCaProv,
    pKeyInfo_CA->dwKeySpec,
    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
    X509_CERT_TO_BE_SIGNED,
    (void*)&serverCertInfo,
    &signAlgo,
    NULL,
    pbEncodedCert_SERVER,
    &cbEncodedCert_SERVER
))
{
    LocalFree(pbEnhancedUsage);
    LocalFree(pbUsage);
    LocalFree(pbEncodedBasicConstraints);
    CertFreeCertificateContext(pCACertContext);
    LocalFree(pbEncodedCert_SERVER);
    CryptReleaseContext(hCaProv, 0);
    CertCloseStore(hStoreRoot, 0);
    throw std::runtime_error("Unable to sign and encode certificate");
}

//free up a bunch of memory we don't need anymore
CertFreeCertificateContext(pCACertContext);
CryptReleaseContext(hCaProv, 0);
CertCloseStore(hStoreRoot, 0);
LocalFree(pbEnhancedUsage);
LocalFree(pbUsage);
LocalFree(pbEncodedBasicConstraints);

//convert to B64 (call #1 to get length)
if (!CryptBinaryToStringA(
    pbEncodedCert_SERVER,
    cbEncodedCert_SERVER,
    CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCRLF,
    NULL,
    &dwB64CertificateLength
))
{
    LocalFree(pbEncodedCert_SERVER);
    throw std::runtime_error("Could not get size of B64 string for server certificate");
}

//allocate space based on call #1
lpstrServerCertificate = (LPSTR)LocalAlloc(0, dwB64CertificateLength);

//convert to B64 (call #2 to encode)
if (!CryptBinaryToStringA(
    pbEncodedCert_SERVER,
    cbEncodedCert_SERVER,
    CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCRLF,
    lpstrServerCertificate,
    &dwB64CertificateLength
))
{
    LocalFree(pbEncodedCert_SERVER);
    LocalFree(lpstrServerCertificate);
    throw std::runtime_error("Could not make B64 string of server certificate");
}

//put the certificate text into a std::string to pass it out of the function and be done
sCertificate = lpstrServerCertificate;

//free resources
LocalFree(pbEncodedCert_SERVER);
LocalFree(lpstrServerCertificate);

连连呢?我觉得我可能在这里犯了一个简单的错误,但我不知道是什么。

1 个答案:

答案 0 :(得分:0)

我认为CryptBinaryToString实际上会在第一次传递时将结果转换为B64 ...由于某种原因需要另一次传递。似乎愚蠢的是必须调用相同的功能4次才能完成这项工作但显然是必要的。我添加了这段代码并在sCertificate上调用了上面的代码,现在我在B64中有一些可行的东西。去搞清楚。希望另一个人从中得到一些东西。

bool UTIL::EncodeB64(
    std::string sToEncode, //data to encode in B64 [IN]
    std::string & sEncoded //encoded data [OUT]
    )
{
    sEncoded = "";
    LPSTR lpstrEncoded = NULL;
    DWORD dwB64Length;
    std::vector<BYTE> vcharBytes(sToEncode.begin(), sToEncode.end());

    //convert to B64 (call #1 to get length)
    if (!CryptBinaryToStringA(
        &vcharBytes[0],
        vcharBytes.size(),
        CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
        NULL,
        &dwB64Length
    ))
    {
        //crashed and burned
        return false;
    }

    //allocate space based on call #1
    lpstrEncoded = (LPSTR)LocalAlloc(0, dwB64Length);

    //convert to B64 (call #2 to encode)
    if (!CryptBinaryToStringA(
        &vcharBytes[0],
        vcharBytes.size(),
        CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
        lpstrEncoded,
        &dwB64Length
    ))
    {
        //crashed and burned
        LocalFree(lpstrEncoded);
        return false;
    }

    //set result that we are going to pass out
    sEncoded = lpstrEncoded;

    //free memory
    LocalFree(lpstrEncoded);

    //success
    return true;
}

添加到调用代码:

std::string sB64Pass1Certificate = lpstrServerCertificate;

LocalFree(pbEncodedCert_SERVER);
LocalFree(lpstrServerCertificate);

if (!EncodeB64(
    sB64Pass1Certificate,
    sCertificate
))
{
    throw std::runtime_error("Could not make B64 string of server certificate (second pass)");
}