From 81bfe457ed2e757f2806fa7fdbbb06257c5e81f8 Mon Sep 17 00:00:00 2001 From: Maxwell McKee <66395252+mamckee@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:01:33 -0400 Subject: [PATCH] Fixes for tpm2 (#84) * Expose EC X and Y as parameters * Make AES-CFB compatible with OpenSSL stream cipher calling pattern * Cleanup * PR comments, address in == out case * Comment --- SymCryptProvider/src/ciphers/p_scossl_aes.c | 255 +++++++++++++++--- .../src/keymgmt/p_scossl_ecc_keymgmt.c | 86 ++++++ 2 files changed, 305 insertions(+), 36 deletions(-) diff --git a/SymCryptProvider/src/ciphers/p_scossl_aes.c b/SymCryptProvider/src/ciphers/p_scossl_aes.c index 51ed03d..a2e9f84 100644 --- a/SymCryptProvider/src/ciphers/p_scossl_aes.c +++ b/SymCryptProvider/src/ciphers/p_scossl_aes.c @@ -22,6 +22,9 @@ static const OSSL_PARAM p_scossl_aes_generic_param_types[] = { OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL), OSSL_PARAM_int(OSSL_CIPHER_PARAM_AEAD, NULL), OSSL_PARAM_int(OSSL_CIPHER_PARAM_CUSTOM_IV, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_CTS, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_HAS_RAND_KEY, NULL), OSSL_PARAM_END}; static const OSSL_PARAM p_scossl_aes_generic_gettable_ctx_param_types[] = { @@ -236,11 +239,11 @@ static SCOSSL_STATUS p_scossl_aes_copy_mac(_Inout_ SCOSSL_AES_CTX *ctx, return SCOSSL_SUCCESS; } -static SCOSSL_STATUS p_scossl_aes_generic_update(_Inout_ SCOSSL_AES_CTX *ctx, - _Out_writes_bytes_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, - _In_reads_bytes_(inl) const unsigned char *in, size_t inl) +static SCOSSL_STATUS p_scossl_aes_generic_block_update(_Inout_ SCOSSL_AES_CTX *ctx, + _Out_writes_bytes_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, + _In_reads_bytes_(inl) const unsigned char *in, size_t inl) { - size_t cbBytesInFullBlocks = 0; + SIZE_T cbInFullBlocks = 0; *outl = 0; if (inl == 0) @@ -332,7 +335,7 @@ static SCOSSL_STATUS p_scossl_aes_generic_update(_Inout_ SCOSSL_AES_CTX *ctx, // The buffer may already be full for padded decrypt if (ctx->cbBuf < SYMCRYPT_AES_BLOCK_SIZE) { - size_t cbBufRemaining = SYMCRYPT_AES_BLOCK_SIZE - ctx->cbBuf; + SIZE_T cbBufRemaining = SYMCRYPT_AES_BLOCK_SIZE - ctx->cbBuf; if (inl < cbBufRemaining) { cbBufRemaining = inl; @@ -361,34 +364,36 @@ static SCOSSL_STATUS p_scossl_aes_generic_update(_Inout_ SCOSSL_AES_CTX *ctx, *outl += SYMCRYPT_AES_BLOCK_SIZE; outsize -= SYMCRYPT_AES_BLOCK_SIZE; ctx->cbBuf = 0; + + SymCryptWipeKnownSize(ctx->buf, SYMCRYPT_AES_BLOCK_SIZE); } } // Get the remaining number of whole blocks in inl - cbBytesInFullBlocks = inl & ~(SYMCRYPT_AES_BLOCK_SIZE-1); + cbInFullBlocks = inl & ~(SYMCRYPT_AES_BLOCK_SIZE-1); // Decrypt with padding. Ensure the last block is buffered // for the call to cipher_final so padding is removed if (!ctx->encrypt && ctx->pad && - cbBytesInFullBlocks > 0 && - cbBytesInFullBlocks == inl) + cbInFullBlocks > 0 && + cbInFullBlocks == inl) { - cbBytesInFullBlocks -= SYMCRYPT_AES_BLOCK_SIZE; + cbInFullBlocks -= SYMCRYPT_AES_BLOCK_SIZE; } // in still contains whole blocks, encrypt available blocks - if (cbBytesInFullBlocks > 0) + if (cbInFullBlocks > 0) { - if (!ctx->cipher(ctx, out, NULL, outsize, in, cbBytesInFullBlocks)) + if (!ctx->cipher(ctx, out, NULL, outsize, in, cbInFullBlocks)) { ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); return SCOSSL_FAILURE; } - in += cbBytesInFullBlocks; - inl -= cbBytesInFullBlocks; - *outl += cbBytesInFullBlocks; + in += cbInFullBlocks; + inl -= cbInFullBlocks; + *outl += cbInFullBlocks; } // Buffer any remaining data @@ -417,8 +422,46 @@ static SCOSSL_STATUS p_scossl_aes_generic_update(_Inout_ SCOSSL_AES_CTX *ctx, return SCOSSL_SUCCESS; } -static SCOSSL_STATUS p_scossl_aes_generic_final(_Inout_ SCOSSL_AES_CTX *ctx, - _Out_writes_bytes_opt_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize) +static SCOSSL_STATUS p_scossl_aes_generic_stream_update(_Inout_ SCOSSL_AES_CTX *ctx, + _Out_writes_bytes_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, + _In_reads_bytes_(inl) const unsigned char *in, size_t inl) +{ + if (inl == 0) + { + return SCOSSL_SUCCESS; + } + + if (outsize < inl) + { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return SCOSSL_FAILURE; + } + + if (!ctx->cipher(ctx, out, outl, outsize, in, inl)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return SCOSSL_FAILURE; + } + + if (!ctx->encrypt && + ctx->tlsVersion > 0 && + ctx->tlsMacSize > 0) + { + if (ctx->tlsMacSize > *outl) + { + ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED); + return SCOSSL_FAILURE; + } + + ctx->tlsMac = out + (*outl - ctx->tlsMacSize); + *outl -= ctx->tlsMacSize; + } + + return SCOSSL_SUCCESS; +} + +static SCOSSL_STATUS p_scossl_aes_generic_block_final(_Inout_ SCOSSL_AES_CTX *ctx, + _Out_writes_bytes_opt_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize) { if (ctx->tlsVersion > 0) { @@ -504,6 +547,13 @@ cleanup: return SymCryptMapUint32(scError, SCOSSL_FAILURE, scErrorMap, 1); } +static SCOSSL_STATUS p_scossl_aes_generic_stream_final(ossl_unused SCOSSL_AES_CTX *ctx, + ossl_unused unsigned char *out, ossl_unused size_t *outl, ossl_unused size_t outsize) +{ + *outl = 0; + return SCOSSL_SUCCESS; +} + static SCOSSL_STATUS p_scossl_aes_generic_cipher(_Inout_ SCOSSL_AES_CTX *ctx, _Out_writes_bytes_opt_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, _In_reads_bytes_(inl) const unsigned char *in, size_t inl) @@ -584,6 +634,27 @@ SCOSSL_STATUS p_scossl_aes_generic_get_params(_Inout_ OSSL_PARAM params[], return SCOSSL_FAILURE; } + if ((p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS)) != NULL && + !OSSL_PARAM_set_int(p, 0)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return SCOSSL_FAILURE; + } + + if ((p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK)) != NULL && + !OSSL_PARAM_set_int(p, 0)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return SCOSSL_FAILURE; + } + + if ((p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_HAS_RAND_KEY)) != NULL && + !OSSL_PARAM_set_int(p, 0)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return SCOSSL_FAILURE; + } + return SCOSSL_SUCCESS; } @@ -743,7 +814,8 @@ static SCOSSL_STATUS scossl_aes_ecb_cipher(_Inout_ SCOSSL_AES_CTX *ctx, } static SCOSSL_STATUS p_scossl_aes_cfb_cipher_internal(_Inout_ SCOSSL_AES_CTX *ctx, SIZE_T cbShift, - _Out_writes_bytes_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, + _Inout_updates_(SYMCRYPT_AES_BLOCKSIZE) PBYTE pbChainingValue, + _Out_writes_bytes_(*outl) unsigned char *out, _Out_opt_ size_t *outl, size_t outsize, _In_reads_bytes_(inl) const unsigned char *in, size_t inl) { if (outsize < inl) @@ -759,31 +831,142 @@ static SCOSSL_STATUS p_scossl_aes_cfb_cipher_internal(_Inout_ SCOSSL_AES_CTX *ct if (ctx->encrypt) { - SymCryptCfbEncrypt(SymCryptAesBlockCipher, cbShift, &ctx->key, ctx->pbChainingValue, in, out, inl); + SymCryptCfbEncrypt(SymCryptAesBlockCipher, cbShift, &ctx->key, pbChainingValue, in, out, inl); } else { - SymCryptCfbDecrypt(SymCryptAesBlockCipher, cbShift, &ctx->key, ctx->pbChainingValue, in, out, inl); + SymCryptCfbDecrypt(SymCryptAesBlockCipher, cbShift, &ctx->key, pbChainingValue, in, out, inl); } return SCOSSL_SUCCESS; } +// AES-CFB requires some special buffering logic due to implementation +// differences between OpenSSL and SymCrypt. SymCrypt will only encrypt +// in multiples of the shift size, but OpenSSL expects the entirety of +// inl to be encrypted in each update call. e.g. if inl is 36, SymCrypt +// will only encrypt 32 bytes, but OpenSSL expects 36 bytes to be encrypted. +// To handle this, any remaining data is buffered, and the previous chaining +// value is saved for the next call. If any data is in the buffer from a +// previous call, the remaining space in the buffer is filled and +// encrypted/decrypted with the previous chaining value before continuing. static SCOSSL_STATUS scossl_aes_cfb_cipher(_Inout_ SCOSSL_AES_CTX *ctx, _Out_writes_bytes_opt_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, _In_reads_bytes_(inl) const unsigned char *in, size_t inl) { - return p_scossl_aes_cfb_cipher_internal(ctx, SYMCRYPT_AES_BLOCK_SIZE, out, outl, outsize, in, inl); + BYTE pbPartialBufOut[SYMCRYPT_AES_BLOCK_SIZE]; + BYTE pbChainingValueLast[SYMCRYPT_AES_BLOCK_SIZE]; + SIZE_T cbBufRemaining; + SIZE_T cbInFullBlocks; + SIZE_T cbInRemaining; + + if (outl != NULL) + { + *outl = inl; + } + + if (ctx->cbBuf > 0) + { + // Last update call was a partial block. Fill buffer and perform cipher + // with previous chaining value before continuing. + cbBufRemaining = SYMCRYPT_MIN(SYMCRYPT_AES_BLOCK_SIZE - ctx->cbBuf, inl); + + // Save the chaining value for the next call in case ctx->cbBuf + inl < cbBufRemaining + memcpy(pbChainingValueLast, ctx->pbChainingValue, SYMCRYPT_AES_BLOCK_SIZE); + memcpy(ctx->buf + ctx->cbBuf, in, cbBufRemaining); + + if (p_scossl_aes_cfb_cipher_internal( + ctx, + SYMCRYPT_AES_BLOCK_SIZE, + ctx->pbChainingValue, + pbPartialBufOut, NULL, SYMCRYPT_AES_BLOCK_SIZE, + ctx->buf, SYMCRYPT_AES_BLOCK_SIZE) != SCOSSL_SUCCESS) + { + return SCOSSL_FAILURE; + } + + memcpy(out, pbPartialBufOut + ctx->cbBuf, cbBufRemaining); + + // Advance pointers and counters + out += cbBufRemaining; + outsize -= cbBufRemaining; + + in += cbBufRemaining; + inl -= cbBufRemaining; + + ctx->cbBuf += cbBufRemaining; + if (ctx->cbBuf == SYMCRYPT_AES_BLOCK_SIZE) + { + ctx->cbBuf = 0; + SymCryptWipeKnownSize(ctx->buf, SYMCRYPT_AES_BLOCK_SIZE); + } + else + { + memcpy(ctx->pbChainingValue, pbChainingValueLast, SYMCRYPT_AES_BLOCK_SIZE); + } + } + + cbInFullBlocks = inl & ~(SYMCRYPT_AES_BLOCK_SIZE-1); + cbInRemaining = inl - cbInFullBlocks; + + if (cbInFullBlocks > 0) + { + if (ctx->cbBuf != 0) + { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return SCOSSL_FAILURE; + } + + if (p_scossl_aes_cfb_cipher_internal( + ctx, + SYMCRYPT_AES_BLOCK_SIZE, + ctx->pbChainingValue, + out, NULL, outsize, + in, cbInFullBlocks) != SCOSSL_SUCCESS) + { + return SCOSSL_FAILURE; + } + } + + if (cbInRemaining > 0) + { + // Encrypt any extra bytes and save the chaining value for the next call + memcpy(pbChainingValueLast, ctx->pbChainingValue, SYMCRYPT_AES_BLOCK_SIZE); + + memcpy(ctx->buf, in + cbInFullBlocks, cbInRemaining); + ctx->cbBuf = cbInRemaining; + + out += cbInFullBlocks; + outsize -= cbInFullBlocks; + + if (p_scossl_aes_cfb_cipher_internal( + ctx, + SYMCRYPT_AES_BLOCK_SIZE, + ctx->pbChainingValue, + pbPartialBufOut, NULL, SYMCRYPT_AES_BLOCK_SIZE, + ctx->buf, SYMCRYPT_AES_BLOCK_SIZE) != SCOSSL_SUCCESS) + { + return SCOSSL_FAILURE; + } + + memcpy(out, pbPartialBufOut, ctx->cbBuf); + + // Since this was a partial block, the next update call will fill the buffer + // and encrypt/decrypt with the same chaining value + memcpy(ctx->pbChainingValue, pbChainingValueLast, SYMCRYPT_AES_BLOCK_SIZE); + } + + return SCOSSL_SUCCESS; } static SCOSSL_STATUS scossl_aes_cfb8_cipher(_Inout_ SCOSSL_AES_CTX *ctx, _Out_writes_bytes_opt_(*outl) unsigned char *out, _Out_ size_t *outl, size_t outsize, _In_reads_bytes_(inl) const unsigned char *in, size_t inl) { - return p_scossl_aes_cfb_cipher_internal(ctx, 1, out, outl, outsize, in, inl); + return p_scossl_aes_cfb_cipher_internal(ctx, 1, ctx->pbChainingValue, out, outl, outsize, in, inl); } -#define IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(kbits, ivlen, lcmode, UCMODE) \ +#define IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(kbits, ivlen, lcmode, UCMODE, type) \ SCOSSL_AES_CTX *p_scossl_aes_##kbits##_##lcmode##_newctx(_In_ SCOSSL_PROVCTX *provctx) \ { \ SCOSSL_COMMON_ALIGNED_ALLOC(ctx, OPENSSL_malloc, SCOSSL_AES_CTX); \ @@ -812,8 +995,8 @@ static SCOSSL_STATUS scossl_aes_cfb8_cipher(_Inout_ SCOSSL_AES_CTX *ctx, {OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))p_scossl_aes_generic_freectx}, \ {OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))p_scossl_aes_generic_encrypt_init}, \ {OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))p_scossl_aes_generic_decrypt_init}, \ - {OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))p_scossl_aes_generic_update}, \ - {OSSL_FUNC_CIPHER_FINAL, (void (*)(void))p_scossl_aes_generic_final}, \ + {OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))p_scossl_aes_generic_##type##_update}, \ + {OSSL_FUNC_CIPHER_FINAL, (void (*)(void))p_scossl_aes_generic_##type##_final}, \ {OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))p_scossl_aes_generic_cipher}, \ {OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))p_scossl_aes_##kbits##_##lcmode##_get_params}, \ {OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))p_scossl_aes_generic_get_ctx_params}, \ @@ -823,21 +1006,21 @@ static SCOSSL_STATUS scossl_aes_cfb8_cipher(_Inout_ SCOSSL_AES_CTX *ctx, {OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))p_scossl_aes_generic_settable_ctx_params}, \ {0, NULL}}; -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(128, SYMCRYPT_AES_BLOCK_SIZE, cbc, CBC) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(192, SYMCRYPT_AES_BLOCK_SIZE, cbc, CBC) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(256, SYMCRYPT_AES_BLOCK_SIZE, cbc, CBC) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(128, SYMCRYPT_AES_BLOCK_SIZE, cbc, CBC, block) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(192, SYMCRYPT_AES_BLOCK_SIZE, cbc, CBC, block) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(256, SYMCRYPT_AES_BLOCK_SIZE, cbc, CBC, block) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(128, 0, ecb, ECB) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(192, 0, ecb, ECB) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(256, 0, ecb, ECB) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(128, 0, ecb, ECB, block) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(192, 0, ecb, ECB, block) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(256, 0, ecb, ECB, block) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(128, SYMCRYPT_AES_BLOCK_SIZE, cfb, CFB) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(192, SYMCRYPT_AES_BLOCK_SIZE, cfb, CFB) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(256, SYMCRYPT_AES_BLOCK_SIZE, cfb, CFB) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(128, SYMCRYPT_AES_BLOCK_SIZE, cfb, CFB, stream) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(192, SYMCRYPT_AES_BLOCK_SIZE, cfb, CFB, stream) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(256, SYMCRYPT_AES_BLOCK_SIZE, cfb, CFB, stream) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(128, SYMCRYPT_AES_BLOCK_SIZE, cfb8, CFB) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(192, SYMCRYPT_AES_BLOCK_SIZE, cfb8, CFB) -IMPLEMENT_SCOSSL_AES_BLOCK_CIPHER(256, SYMCRYPT_AES_BLOCK_SIZE, cfb8, CFB) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(128, SYMCRYPT_AES_BLOCK_SIZE, cfb8, CFB, stream) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(192, SYMCRYPT_AES_BLOCK_SIZE, cfb8, CFB, stream) +IMPLEMENT_SCOSSL_AES_GENERIC_CIPHER(256, SYMCRYPT_AES_BLOCK_SIZE, cfb8, CFB, stream) #ifdef __cplusplus } diff --git a/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c b/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c index b748565..3a1d0de 100644 --- a/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c +++ b/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c @@ -46,6 +46,8 @@ static const OSSL_PARAM p_scossl_ecc_keymgmt_gettable_param_types[] = { OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), OSSL_PARAM_END}; static const OSSL_PARAM p_scossl_ecc_keymgmt_settable_param_types[] = { @@ -461,6 +463,85 @@ cleanup: return keyCtx; } +static SCOSSL_STATUS p_scossl_ecc_keymgmt_get_pubkey_point(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, _Inout_ OSSL_PARAM params[]) +{ + PBYTE pbPublicKey = NULL; + SIZE_T cbPublicKey; + BIGNUM *bnPubX = NULL; + BIGNUM *bnPubY = NULL; + SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; + SCOSSL_STATUS ret = SCOSSL_FAILURE; + + OSSL_PARAM *paramPubX = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_PUB_X); + OSSL_PARAM *paramPubY = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_PUB_Y); + + if (paramPubX == NULL && + paramPubY == NULL) + { + return SCOSSL_SUCCESS; + } + + cbPublicKey = SymCryptEckeySizeofPublicKey(keyCtx->key, SYMCRYPT_ECPOINT_FORMAT_XY); + + if ((pbPublicKey = OPENSSL_malloc(cbPublicKey)) == NULL) + { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto cleanup; + } + + scError = SymCryptEckeyGetValue( + keyCtx->key, + NULL, 0, + pbPublicKey, cbPublicKey, + SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, + SYMCRYPT_ECPOINT_FORMAT_XY, + 0 ); + if (scError != SYMCRYPT_NO_ERROR) + { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + goto cleanup; + } + + if (paramPubX != NULL) + { + if ((bnPubX = BN_bin2bn(pbPublicKey, cbPublicKey/2, NULL)) == NULL) + { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto cleanup; + } + + if (!OSSL_PARAM_set_BN(paramPubX, bnPubX)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + goto cleanup; + } + } + + if (paramPubY != NULL) + { + if ((bnPubY = BN_bin2bn(pbPublicKey + (cbPublicKey/2), cbPublicKey/2, NULL)) == NULL) + { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto cleanup; + } + + if (!OSSL_PARAM_set_BN(paramPubY, bnPubY)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + goto cleanup; + } + } + + ret = SCOSSL_SUCCESS; + +cleanup: + OPENSSL_free(pbPublicKey); + BN_free(bnPubX); + BN_free(bnPubY); + + return ret; +} + static SCOSSL_STATUS p_scossl_ecc_keymgmt_get_params(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, _Inout_ OSSL_PARAM params[]) { PBYTE pbEncodedKey = NULL; @@ -571,6 +652,11 @@ static SCOSSL_STATUS p_scossl_ecc_keymgmt_get_params(_In_ SCOSSL_ECC_KEY_CTX *ke // General ECDH only if (!keyCtx->isX25519) { + if (!p_scossl_ecc_keymgmt_get_pubkey_point(keyCtx, params)) + { + goto cleanup; + } + if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST)) != NULL && !OSSL_PARAM_set_utf8_string(p, SCOSSL_ECC_DEFAULT_DIGEST)) {