std::vector BcryptECDiffieHellman::ExportSubjectPublicKeyInfo()

in azure-protected-vm-secrets/Windows/BcryptECDiffieHellman.cpp [564:720]


std::vector<unsigned char> BcryptECDiffieHellman::ExportSubjectPublicKeyInfo() const
{
	std::vector<unsigned char> result;
#ifndef PLATFORM_UNIX
    DWORD publicKeyBlobLen = 0;
    NTSTATUS status = STATUS_SUCCESS;
    CRYPT_ECC_PRIVATE_KEY_INFO eccPrivateInfo = { 0 };
    CRYPT_PRIVATE_KEY_INFO privateKeyInfo = { 0 };
    DWORD privateKeyInfoLen = 0;
    BYTE* pbCurveParameters = nullptr;
    DWORD cbCurveParameters = 0;
    BCRYPT_ECCKEY_BLOB* pekb = nullptr;
    CERT_PUBLIC_KEY_INFO publicKeyInfo = { 0 };
    union {
        PVOID pvStructInfo;
        PCERT_INFO pCertInfo;
        PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
    };
    // Get the size of the public key blob
    status = BCryptExportKey(this->hEccKeyHandle, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &publicKeyBlobLen, 0);
    if (status != STATUS_SUCCESS) {
        // LibraryError, Bcrypt subclass, keyError
        throw BcryptError(status, "BCryptExportKey - Get Size - failed.\n",
            ErrorCode::LibraryError_Bcrypt_keyError);
    }
    unsigned char* publicKeyBlob = (unsigned char*)malloc(publicKeyBlobLen);
    if (publicKeyBlob == NULL) {
		// GenericError, Memory subclass, mallocError
        throw std::exception("ECDH - Malloc Fail");
    }
    // Export the public key blob
    status = BCryptExportKey(this->hEccKeyHandle, NULL, BCRYPT_ECCPUBLIC_BLOB, publicKeyBlob, publicKeyBlobLen, &publicKeyBlobLen, 0);
    if (status != STATUS_SUCCESS) {
		// LibraryError, Bcrypt subclass, keyError
        throw BcryptError(status, "BCryptExportKey - Export Key - failed.\n",
            ErrorCode::LibraryError_Bcrypt_keyError);
    }

    pekb = (BCRYPT_ECCKEY_BLOB*)publicKeyBlob;

    CRYPT_BIT_BLOB CryptBitBlob = { 0 };
    CryptBitBlob.cbData = 1;
    CryptBitBlob.pbData = (BYTE*)malloc(1);
    CryptBitBlob.pbData[0] = CERT_KEY_AGREEMENT_KEY_USAGE;
    CryptBitBlob.cUnusedBits = 0;
    // Get the size of the curve parameters
    status = BCryptGetProperty(
        this->hEccKeyHandle,
        BCRYPT_ECC_PARAMETERS,
        NULL,                       // pbOutput
        0,                          // cbOutput
        &cbCurveParameters,
        0                           // dwFlags
    );
    if (status != STATUS_SUCCESS) {
		// LibraryError, Bcrypt subclass, propertyError
        throw BcryptError(status, "BCryptGetProperty Size failed.\n",
            ErrorCode::LibraryError_Bcrypt_propertyError);
    }

    pbCurveParameters = (BYTE*)malloc(cbCurveParameters);
    if (pbCurveParameters == nullptr) {
        // GenericError, Memory subclass, mallocError
        throw std::exception("ECDH - Malloc Failed");
    }
    // Get the curve parameters
    status = BCryptGetProperty(
        this->hEccKeyHandle,
        BCRYPT_ECC_PARAMETERS,
        pbCurveParameters,
        cbCurveParameters,
        &cbCurveParameters,
        0);
    if (status != STATUS_SUCCESS) {
		// LibraryError, Bcrypt subclass, propertyError
        throw BcryptError(status, "BCryptGetProperty Value failed.\n",
            ErrorCode::LibraryError_Bcrypt_propertyError);
    }

    CRYPT_DATA_BLOB CNGECCBlob = { 0 };
    CNGECCBlob.cbData = cbCurveParameters;
    CNGECCBlob.pbData = pbCurveParameters;
    ULONG cbCurveInfo = 0;

    if (!CryptEncodeObject(
        X509_ASN_ENCODING,
        X509_ECC_PARAMETERS,
        &CNGECCBlob,
        NULL,
        &cbCurveInfo))
    {
        // ParsingError, ASN subclass, x509PubKeyError
        throw WinCryptError("CryptEncodeObject 1 failed.", GetLastError(),
            ErrorCode::ParsingError_Asn1_x509PubKeyError);
    }

    ULONG cbPupKeyInfo = sizeof(publicKeyInfo) + sizeof(szOID_ECC_PUBLIC_KEY);

    cbPupKeyInfo += cbCurveInfo;

    publicKeyInfo.PublicKey.cbData = pekb->cbKey * EC_PUBLIC_NUM_COMPONENTS + 1;
    publicKeyInfo.PublicKey.cUnusedBits = 0;
    publicKeyInfo.PublicKey.pbData = (BYTE*)malloc(publicKeyInfo.PublicKey.cbData);
    if (publicKeyInfo.PublicKey.pbData == NULL) {
		// GenericError, Memory subclass, mallocError
        throw std::exception("ECDH - Malloc Fail");
    }
    ZeroMemory(publicKeyInfo.PublicKey.pbData, publicKeyInfo.PublicKey.cbData);
    publicKeyInfo.PublicKey.pbData[0] = EC_UNCOMPRESSED_BLOB;
    CopyMemory(
		publicKeyInfo.PublicKey.pbData + 1, pekb + 1, pekb->cbKey * EC_PUBLIC_NUM_COMPONENTS);
    publicKeyInfo.Algorithm.Parameters.cbData = cbCurveInfo;
    publicKeyInfo.Algorithm.Parameters.pbData = (BYTE*)malloc(publicKeyInfo.Algorithm.Parameters.cbData);
    if (publicKeyInfo.Algorithm.Parameters.pbData == NULL) {
        // GenericError, Memory subclass, mallocError
        throw std::exception("ECDH - Malloc Fail");
    }
    publicKeyInfo.Algorithm.pszObjId = (LPSTR)malloc(sizeof(szOID_ECC_PUBLIC_KEY));
    if (publicKeyInfo.Algorithm.pszObjId == NULL) {
        // GenericError, Memory subclass, mallocError
        throw std::exception("ECDH - Malloc Fail");
    }
    ZeroMemory(publicKeyInfo.Algorithm.Parameters.pbData, publicKeyInfo.Algorithm.Parameters.cbData);
    if (!CryptEncodeObject(
        X509_ASN_ENCODING,
        X509_ECC_PARAMETERS,
        &CNGECCBlob,
        publicKeyInfo.Algorithm.Parameters.pbData,
        &publicKeyInfo.Algorithm.Parameters.cbData))
    {
        // ParsingError, ASN subclass, x509PubKeyError
        throw WinCryptError("CryptEncodeObject 2 failed.", GetLastError(),
            ErrorCode::ParsingError_Asn1_x509PubKeyError);
    }
    CopyMemory(
		publicKeyInfo.Algorithm.pszObjId,
		szOID_ECC_PUBLIC_KEY,
		sizeof(szOID_ECC_PUBLIC_KEY));

	ULONG derPublicBytesLen = 0;
	unsigned char* derPublicBytes = nullptr;
    if (!CryptEncodeObjectEx(
        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
        X509_PUBLIC_KEY_INFO,
        (BYTE*)(&publicKeyInfo),
        CRYPT_ENCODE_ALLOC_FLAG,
        NULL,
        &derPublicBytes, &derPublicBytesLen))
    {
		// ParsingError, ASN subclass, x509PubKeyError
        throw WinCryptError("CryptEncodeObjectEx 1 failed.", GetLastError(),
            ErrorCode::ParsingError_Asn1_x509PubKeyError);
	}
	result = std::vector<unsigned char>(derPublicBytes, derPublicBytes + derPublicBytesLen);
#endif // !PLATFORM_UNIX
	return result;
}