void BcryptECDiffieHellman::ImportSubjectPublicKeyInfo()

in azure-protected-vm-secrets/Windows/BcryptECDiffieHellman.cpp [210:319]


void BcryptECDiffieHellman::ImportSubjectPublicKeyInfo(std::vector<unsigned char> const&derPublicKey) {
#ifndef PLATFORM_UNIX
    DWORD          publicKeyInfoLen = 0;
    HCRYPTPROV     hProv = 0;
    HCRYPTKEY      hKey = 0;
    CERT_PUBLIC_KEY_INFO certPubInfo{};
    ULONG cb = 0;
    NTSTATUS status;
    union {
        PVOID pvStructInfo;
        PCERT_INFO pCertInfo;
        PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
    };

    if (!CryptDecodeObjectEx(
        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
        X509_PUBLIC_KEY_INFO,
        derPublicKey.data(), derPublicKey.size(),
        CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
        NULL,
        &pvStructInfo, &cb))
    {
		// ParsingError, ASN subclass, x509PubKeyError
        throw WinCryptError("CryptDecodeObjectEx 1 failed.", GetLastError(),
            ErrorCode::ParsingError_Asn1_x509PubKeyError);
    }
    LIBSECRETS_LOG(
        LogLevel::Debug,
        "EC Diffie Hellman Import",
        "Public key size: PublicKeyInfo->PublicKey.cbData %d",
        PublicKeyInfo->PublicKey.cbData);

    CRYPT_ECC_PRIVATE_KEY_INFO* eccPrivateInfo = nullptr;
    DWORD eccKeyInfoLen = 0;
    ULONG cbPubKey = 0;
    if (NULL != PublicKeyInfo->PublicKey.pbData &&
        PublicKeyInfo->PublicKey.cbData > 0
        )
    {
        if (
            EC_UNCOMPRESSED_BLOB != PublicKeyInfo->PublicKey.pbData[0] &&
            EC_UNKNOWN_ASN_BYTE  != PublicKeyInfo->PublicKey.pbData[0] &&
            EC_UNKNOWN_ASN_BYTE2 != PublicKeyInfo->PublicKey.pbData[0]
            )
        {
            LIBSECRETS_LOG(
                LogLevel::Debug,
                "EC Diffie Hellman Import",
                "Error with public key info: PublicKeyInfo->PublicKey.pbData[0] %x",
                PublicKeyInfo->PublicKey.pbData[0]);

        }

        cbPubKey = (PublicKeyInfo->PublicKey.cbData - 1) / EC_PUBLIC_NUM_COMPONENTS;
    }
    else
    {
        cbPubKey = 0;
    }

    LIBSECRETS_LOG(LogLevel::Debug, "EC Diffie Hellman Import", "Passed private validation", nullptr);

    ULONG cbKey = cbPubKey;
    ULONG cbKeyBlob = sizeof(BCRYPT_ECCKEY_BLOB) + EC_PUBLIC_NUM_COMPONENTS * cbKey;
    BCRYPT_ECCKEY_BLOB* pekb = (BCRYPT_ECCKEY_BLOB*)malloc(cbKeyBlob);
    if (pekb == NULL) {
        // GenericError, Memory subclass, mallocError
        throw std::exception("ECDH - Malloc Failed");
    }
    ZeroMemory(pekb, cbKeyBlob);

    pekb->dwMagic = BCRYPT_ECDH_PUBLIC_P256_MAGIC;
    pekb->cbKey = cbKey;
    BYTE* pb = NULL;

    if (cbPubKey > 0)
    {
        if (cbKey == cbPubKey)
        {
            CopyMemory(pekb + 1, PublicKeyInfo->PublicKey.pbData + 1, EC_PUBLIC_NUM_COMPONENTS * cbKey);
        }
        else
        {
            ULONG off = 0;
            pb = (BYTE*)(pekb + 1);
            off = cbKey - cbPubKey;
            CopyMemory(pb + off, PublicKeyInfo->PublicKey.pbData + 1, cbPubKey);
            CopyMemory(pb + cbKey + off, PublicKeyInfo->PublicKey.pbData + 1 + cbPubKey, cbPubKey);
        }
    }
    if (PublicKeyInfo != nullptr) {
        LocalFree(PublicKeyInfo);
    }

    if (cbKeyBlob != sizeof(BCRYPT_ECCKEY_BLOB) + pekb->cbKey * EC_PUBLIC_NUM_COMPONENTS) {
        // ParsingError, ASN subclass, x509PubKeyError
        throw WinCryptError("Invalid key blob", 0,
            ErrorCode::ParsingError_Asn1_x509PubKeyError);
    }

    status = BCryptImportKeyPair(this->hEcHandle, NULL, BCRYPT_ECCPUBLIC_BLOB, &(this->hEccKeyHandle), (PUCHAR)(pekb), cbKeyBlob, 0);

    if (status != STATUS_SUCCESS) {
		// LibraryError, Bcrypt subclass, keyError
        throw BcryptError(status, "BCryptImportKeyPair 1 failed.\n",
            ErrorCode::LibraryError_Bcrypt_keyError);
    }

#endif // !PLATFORM_UNIX
}