My goal is to use CryptoAPI to take some bytes of a signed and encoded certificate made in CryptoAPI and convert them to B64. Problem is, the certificate header is being tacked on but the output is not B64!
My output:
-----BEGIN CERTIFICATE-----MIIDfjCCAmagAwIBAgIBAjANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xEDAOBgNVBAoMB0FVVE9TT0wxDzANBgNVBAsMBkNNREVQVDEUMBIGA1UEAwwLbmFtZWRwaXBlQ0EwHhcNMTgwMTI2MTk0NDQ2WhcNMTkwMTI2MTk0NDQ2WjBlMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xDDAKBgNVBAoMA0RpczEmMCQGA1UEAwwdU1ZSLkNNMDA0MDlEOTg4RTk1LjE1MTY5OTQ5OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD28NOZkuJbUsU0COQFrJgMgzGaj/afj6lYKZyTr5oXtenSmTAXN0WJE7Wd7DCfKqPpbnui4mb62Tgn3NCyMyEHY5jzFUWaUIchlmVzkamQzkmE3g99Fhj3EZP9zAEQE7qs7p5aKcgzIHuMRDB16Ap7/GcFLTUBXcval17yOyU+J9csiywTRA54IK8nvtXzYVvgDSKXOh02VEU9RIjE4C069PKGg04lwZNHm8KvuPJn70PXQQnDaoSkbyvh46lKGhJUsNzNsV0Dpk1owrV9jCCUhpOKdA61Ye8P1oFgLkyu8VV4FjJL7/t7AwaV7AgV7fVtOQ1fZ1HU4VheDD+Q23snAgMBAAGjNjA0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIFoDANBgNVHQoEBjAEAwIGQDANBgkqhkiG9w0BAQsFAAOCAQEAShaqwVJvEjg9n4Tw24hBvl5pXpRGlUjgOQHDsk9sf8WWlDQWZzdRbaw9Y2QBEPuBbxbnF/voiUwYIhWrIYZziZDmx4mHuM1tt7Dyo79pAaJ6KrYkEzOoLP9VCuC1qHsux9cwYb1WiJmJtIZi22aFvAXDCQ3cDr6ej+PbgrXOL+oaS3b95F2ds6zWhDjyFwBLldkAXB4P/GiiOnS3X85DVxWLzY+y88hoKqBYJq5vaAIdLHlqA6jZJYuR2VUjVixggLclAeGUYO9ljLcyS9aer0DFJvdCMKJyUfcN6t6s/tDsKO7nrJrPNIVxbXfg8KzVnWG3Px9KTF9u9bt2G3kJNg==-----END CERTIFICATE-----
If I paste the above text here and try to decode it, it fails...its not B64: https://www.base64decode.org/
If I go to https://www.base64encode.org/ and paste in the above, the tool converts it to B64 which I can submit via the in-house API call I need to make and OpenSSL is happy with it. I need to use the last two function calls in the code sample to do this, but its not working. No errors are being thrown.
Code:
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);
Suggestions? I feel I might be doing a simple mistake here but I don't know what.