void BcryptECDiffieHellman::ImportPkcs8PrivateKey()

in azure-protected-vm-secrets/Windows/BcryptECDiffieHellman.cpp [83:208]


void BcryptECDiffieHellman::ImportPkcs8PrivateKey(std::vector<unsigned char> const&derPrivateKey)
{
#ifndef PLATFORM_UNIX
    PCRYPT_PRIVATE_KEY_INFO privateKeyInfo = nullptr;
    DWORD publicKeyInfoLen = 0;
    CRYPT_ECC_PRIVATE_KEY_INFO* eccPrivateInfo = nullptr;
    DWORD eccKeyInfoLen = 0;
    ULONG cbPubKey = 0;
    BCRYPT_ECCKEY_BLOB* pekb = nullptr;
    NTSTATUS status = STATUS_SUCCESS;
    if (!CryptDecodeObjectEx(
            X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
            PKCS_PRIVATE_KEY_INFO,
            derPrivateKey.data(), derPrivateKey.size(),
            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
            NULL,
            &privateKeyInfo, &publicKeyInfoLen))
    {
        // ParsingError, ASN subclass, x509PrivKeyError
        throw WinCryptError("CryptDecodeObjectEx 1 failed.", GetLastError(),
            ErrorCode::ParsingError_Asn1_x509PrivKeyError);
    }

    if (!CryptDecodeObjectEx(
            X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
            X509_ECC_PRIVATE_KEY,
            privateKeyInfo->PrivateKey.pbData, privateKeyInfo->PrivateKey.cbData,
            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
            NULL,
            &eccPrivateInfo, &eccKeyInfoLen))
    {
        // ParsingError, ASN subclass, x509PrivKeyError
        throw WinCryptError("CryptDecodeObjectEx 2 failed.", GetLastError(),
            ErrorCode::ParsingError_Asn1_x509PrivKeyError);
    }

    if (NULL != eccPrivateInfo->PublicKey.pbData &&
        eccPrivateInfo->PublicKey.cbData > 0)
    {
        if (
            EC_UNCOMPRESSED_BLOB != eccPrivateInfo->PublicKey.pbData[0] &&
            EC_UNKNOWN_ASN_BYTE  != eccPrivateInfo->PublicKey.pbData[0] &&
            EC_UNKNOWN_ASN_BYTE2 != eccPrivateInfo->PublicKey.pbData[0]
            )
        {
            // ParsingError, ASN subclass, x509PrivKeyError
            throw WinCryptError("Error with public key info", 0,
                ErrorCode::ParsingError_Asn1_x509PrivKeyError);
        }
        cbPubKey = (eccPrivateInfo->PublicKey.cbData - 1) / EC_PUBLIC_NUM_COMPONENTS;
    }
    else
    {
        cbPubKey = 0;
    }

    ULONG cbKey = eccPrivateInfo->PrivateKey.cbData;

    if (cbKey < eccPrivateInfo->PrivateKey.cbData ||
        cbKey < cbPubKey)
    {
        LIBSECRETS_LOG(
			LogLevel::Info,
			"EC Diffie Hellman Import",
			"Error with private key info");
    }
    LIBSECRETS_LOG(
        LogLevel::Debug,
        "EC Diffie Hellman Import",
        "Passed private validation");

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

    pekb->dwMagic = BCRYPT_ECDH_PRIVATE_P256_MAGIC;
    pekb->cbKey = cbKey;

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

    pb = (BYTE*)(pekb + 1) + EC_PUBLIC_NUM_COMPONENTS * cbKey;
    CopyMemory(pb + (cbKey - eccPrivateInfo->PrivateKey.cbData),
        eccPrivateInfo->PrivateKey.pbData,
        eccPrivateInfo->PrivateKey.cbData);

    if (privateKeyInfo != nullptr) {
        LocalFree(privateKeyInfo);
    }
    
    if (eccPrivateInfo != nullptr) {
        LocalFree(eccPrivateInfo);
    }

    if (cbKeyBlob != sizeof(BCRYPT_ECCKEY_BLOB) + pekb->cbKey * EC_PRIVATE_NUM_COMPONENTS) {
        // ParsingError, ASN subclass, x509PrivKeyError
        throw WinCryptError("Invalid key blob", 0,
            ErrorCode::ParsingError_Asn1_x509PrivKeyError);
    }
    status = BCryptImportKeyPair(this->hEcHandle, NULL, BCRYPT_ECCPRIVATE_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
}