diff --git a/ScosslCommon/inc/scossl_helpers.h b/ScosslCommon/inc/scossl_helpers.h index 06f1f85..a7122a0 100644 --- a/ScosslCommon/inc/scossl_helpers.h +++ b/ScosslCommon/inc/scossl_helpers.h @@ -118,6 +118,7 @@ typedef enum { SCOSSL_ERR_F_GET_SYMCRYPT_HASH_ALGORITHM, SCOSSL_ERR_F_GET_SYMCRYPT_MAC_ALGORITHM, SCOSSL_ERR_F_HKDF_DERIVE, + SCOSSL_ERR_F_MAC_DUPCTX, SCOSSL_ERR_F_MAC_INIT, SCOSSL_ERR_F_MAC_SET_HMAC_MD, SCOSSL_ERR_F_RSA_DECRYPT, diff --git a/ScosslCommon/src/scossl_helpers.c b/ScosslCommon/src/scossl_helpers.c index 8ada248..ce3f6ff 100644 --- a/ScosslCommon/src/scossl_helpers.c +++ b/ScosslCommon/src/scossl_helpers.c @@ -78,6 +78,7 @@ static ERR_STRING_DATA SCOSSL_ERR_function_strings[] = { {ERR_PACK(0, SCOSSL_ERR_F_GET_SYMCRYPT_HASH_ALGORITHM, 0), "scossl_get_symcrypt_hash_algorithm"}, {ERR_PACK(0, SCOSSL_ERR_F_GET_SYMCRYPT_MAC_ALGORITHM, 0), "scossl_get_symcrypt_hmac_algorithm"}, {ERR_PACK(0, SCOSSL_ERR_F_HKDF_DERIVE, 0), "scossl_hkdf_derive"}, + {ERR_PACK(0, SCOSSL_ERR_F_MAC_DUPCTX, 0), "scossl_mac_dupctx"}, {ERR_PACK(0, SCOSSL_ERR_F_MAC_INIT, 0), "scossl_mac_init"}, {ERR_PACK(0, SCOSSL_ERR_F_MAC_SET_HMAC_MD, 0), "scossl_mac_set_hmac_md"}, {ERR_PACK(0, SCOSSL_ERR_F_RSA_DECRYPT, 0), "scossl_rsa_decrypt"}, diff --git a/ScosslCommon/src/scossl_mac.c b/ScosslCommon/src/scossl_mac.c index f217f1c..66b5814 100644 --- a/ScosslCommon/src/scossl_mac.c +++ b/ScosslCommon/src/scossl_mac.c @@ -109,6 +109,8 @@ SCOSSL_MAC_CTX *scossl_mac_dupctx(SCOSSL_MAC_CTX *ctx) SCOSSL_COMMON_ALIGNED_ALLOC_EX(expandedKey, OPENSSL_malloc, SCOSSL_MAC_EXPANDED_KEY, ctx->pMac->expandedKeySize); if (expandedKey == NULL) { + SCOSSL_LOG_ERROR(SCOSSL_ERR_F_MAC_DUPCTX, ERR_R_MALLOC_FAILURE, + "Failed to aligned allocate expanded key"); goto cleanup; } @@ -118,14 +120,32 @@ SCOSSL_MAC_CTX *scossl_mac_dupctx(SCOSSL_MAC_CTX *ctx) if (ctx->macState != NULL) { + // A caller can potentially initialize a MAC context with state but no key (e.g. HMAC with digest set, but no key yet). + // SymCrypt HMAC and CMAC state copy functions allow us to pass NULL for the expanded key parameter, but the key from + // ctx will be set in copyCtx->macState, which is undesirable. Instead, allocate an empty expanded key in copyCtx. + if (copyCtx->expandedKey == NULL) + { + SCOSSL_COMMON_ALIGNED_ALLOC_EX(expandedKey, OPENSSL_malloc, SCOSSL_MAC_EXPANDED_KEY, ctx->pMac->expandedKeySize); + if (expandedKey == NULL) + { + SCOSSL_LOG_ERROR(SCOSSL_ERR_F_MAC_DUPCTX, ERR_R_MALLOC_FAILURE, + "Failed to aligned allocate expanded key"); + goto cleanup; + } + + copyCtx->expandedKey = expandedKey; + } + SCOSSL_COMMON_ALIGNED_ALLOC_EX(macState, OPENSSL_malloc, SCOSSL_MAC_STATE, ctx->pMac->stateSize); if (macState == NULL) { + SCOSSL_LOG_ERROR(SCOSSL_ERR_F_MAC_DUPCTX, ERR_R_MALLOC_FAILURE, + "Failed to aligned allocate mac state"); goto cleanup; } copyCtx->macState = macState; - ctx->pMacEx->stateCopyFunc(ctx->macState, ctx->expandedKey, copyCtx->macState); + ctx->pMacEx->stateCopyFunc(ctx->macState, copyCtx->expandedKey, copyCtx->macState); } } @@ -311,21 +331,26 @@ SCOSSL_STATUS scossl_mac_init(SCOSSL_MAC_CTX *ctx, { SYMCRYPT_ERROR scError; - if (pbKey != NULL) + if (ctx->pMac == NULL || ctx->macState == NULL) { - if (ctx->expandedKey == NULL) - { - SCOSSL_COMMON_ALIGNED_ALLOC_EX(expandedKey, OPENSSL_malloc, SCOSSL_MAC_EXPANDED_KEY, ctx->pMac->expandedKeySize); - if (expandedKey == NULL) - { - SCOSSL_LOG_ERROR(SCOSSL_ERR_F_MAC_INIT, ERR_R_INTERNAL_ERROR, - "Failed to aligned allocated expanded key"); - return SCOSSL_FAILURE; - } + return SCOSSL_FAILURE; + } - ctx->expandedKey = expandedKey; + if (ctx->expandedKey == NULL) + { + SCOSSL_COMMON_ALIGNED_ALLOC_EX(expandedKey, OPENSSL_malloc, SCOSSL_MAC_EXPANDED_KEY, ctx->pMac->expandedKeySize); + if (expandedKey == NULL) + { + SCOSSL_LOG_ERROR(SCOSSL_ERR_F_MAC_INIT, ERR_R_MALLOC_FAILURE, + "Failed to aligned allocate expanded key"); + return SCOSSL_FAILURE; } + ctx->expandedKey = expandedKey; + } + + if (pbKey != NULL) + { scError = ctx->pMac->expandKeyFunc(ctx->expandedKey, pbKey, cbKey); if (scError != SYMCRYPT_NO_ERROR) diff --git a/SymCryptProvider/src/ciphers/p_scossl_aes.c b/SymCryptProvider/src/ciphers/p_scossl_aes.c index 1bc3f15..c864a58 100644 --- a/SymCryptProvider/src/ciphers/p_scossl_aes.c +++ b/SymCryptProvider/src/ciphers/p_scossl_aes.c @@ -151,7 +151,10 @@ static SCOSSL_STATUS p_scossl_aes_generic_decrypt_init(_Inout_ SCOSSL_AES_CTX *c #define SYMCRYPT_OPENSSL_MASK8_SELECT( _mask, _a, _b ) (SYMCRYPT_FORCE_READ8(&_mask) & _a) | (~(SYMCRYPT_FORCE_READ8(&_mask)) & _b) // Verifies the TLS padding from the end of record, extracts the MAC from the end of -// the unpadded record, and saves the result to ctx->tlsMac. +// the unpadded record, and saves the result to ctx->tlsMac. +// +// If ctx->tlsMacSize is 0 (in the case of encrypt-then-mac), no MAC is extracted, +// but the padding is still verified and removed. // // The MAC will later be fetched through p_scossl_aes_generic_get_ctx_params // This function is adapted from ssl3_cbc_copy_mac in ssl/record/tls_pad.c, and @@ -199,12 +202,6 @@ static SCOSSL_STATUS p_scossl_aes_tls_remove_padding_and_copy_mac( return SCOSSL_FAILURE; } - if ((ctx->tlsMac = OPENSSL_malloc(ctx->tlsMacSize)) == NULL) - { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); - return SCOSSL_FAILURE; - } - // We only care about the tail of the input buffer, which we can index with UINT32 indices // The if() is safe as both cbData and u32 are public values. u32 = ctx->tlsMacSize + 255 + 1; @@ -247,15 +244,25 @@ static SCOSSL_STATUS p_scossl_aes_tls_remove_padding_and_copy_mac( paddingStatus |= (BYTE)((~SYMCRYPT_MASK32_EQ(recordByte, cbPad)) & (~macNotEnded)); } - // MAC rotation - for (i = 0; i < ctx->tlsMacSize; i++) + // Public info, safe to branch + if (ctx->tlsMacSize > 0) { - BYTE macByte = 0; - for (j = 0; j < ctx->tlsMacSize; j++) { - UINT32 match = SYMCRYPT_MASK32_EQ(j, (rotateOffset + i) % ctx->tlsMacSize); - macByte |= rotatedMac[j] & match; + if ((ctx->tlsMac = OPENSSL_malloc(ctx->tlsMacSize)) == NULL) + { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return SCOSSL_FAILURE; + } + + // MAC rotation + for (i = 0; i < ctx->tlsMacSize; i++) + { + BYTE macByte = 0; + for (j = 0; j < ctx->tlsMacSize; j++) { + UINT32 match = SYMCRYPT_MASK32_EQ(j, (rotateOffset + i) % ctx->tlsMacSize); + macByte |= rotatedMac[j] & match; + } + ctx->tlsMac[i] = SYMCRYPT_OPENSSL_MASK8_SELECT(paddingStatus, randMac[i], macByte); } - ctx->tlsMac[i] = SYMCRYPT_OPENSSL_MASK8_SELECT(paddingStatus, randMac[i], macByte); } *pcbData -= (1 + cbPad + ctx->tlsMacSize); @@ -292,11 +299,6 @@ static SCOSSL_STATUS p_scossl_aes_generic_block_update(_Inout_ SCOSSL_AES_CTX *c SIZE_T cbInFullBlocks = 0; *outl = 0; - if (inl == 0) - { - return SCOSSL_SUCCESS; - } - if (ctx->tlsVersion > 0) { // Each update call corresponds to a TLS record and is individually padded diff --git a/SymCryptProvider/src/kem/p_scossl_mlkem.c b/SymCryptProvider/src/kem/p_scossl_mlkem.c index 5903b77..fe577d3 100644 --- a/SymCryptProvider/src/kem/p_scossl_mlkem.c +++ b/SymCryptProvider/src/kem/p_scossl_mlkem.c @@ -14,13 +14,31 @@ extern "C" { #define SCOSSL_MLKEM_SECRET_LENGTH 32 +#ifndef OSSL_KEM_PARAM_IKME +#define OSSL_KEM_PARAM_IKME "ikme" +#endif + +// Older versions of OBJ_create expect a non-NULL OID. This OID is never +// used for hybrid KEM groups, so just use a dummy OID for compatibility. +// These OIDs are the same as the ones used by the OQS provider, since +// OpenSSL at least expects a valid formatted OID. +#if OPENSSL_VERSION_MAJOR == 3 && OPENSSL_VERSION_MINOR < 2 + #define SCOSSL_OID_P256_MLKEM768 "1.3.6.1.4.1.22554.5.7.1" + #define SCOSSL_OID_X25519_MLKEM768 "1.3.6.1.4.1.22554.5.7.2" + #define SCOSSL_OID_P384_MLKEM1024 "1.3.6.1.4.1.22554.5.8.1" +#else + #define SCOSSL_OID_P256_MLKEM768 NULL + #define SCOSSL_OID_X25519_MLKEM768 NULL + #define SCOSSL_OID_P384_MLKEM1024 NULL +#endif + static SCOSSL_MLKEM_GROUP_INFO p_scossl_mlkem_groups[] = { {NID_undef, SCOSSL_OID_MLKEM512, SCOSSL_SN_MLKEM512, SCOSSL_LN_MLKEM512, SYMCRYPT_MLKEM_PARAMS_MLKEM512}, {NID_undef, SCOSSL_OID_MLKEM768, SCOSSL_SN_MLKEM768, SCOSSL_LN_MLKEM768, SYMCRYPT_MLKEM_PARAMS_MLKEM768}, {NID_undef, SCOSSL_OID_MLKEM1024, SCOSSL_SN_MLKEM1024, SCOSSL_LN_MLKEM1024, SYMCRYPT_MLKEM_PARAMS_MLKEM1024}, - {NID_undef, NULL, SCOSSL_SN_P256_MLKEM768, SCOSSL_LN_P256_MLKEM768, SYMCRYPT_MLKEM_PARAMS_MLKEM768}, - {NID_undef, NULL, SCOSSL_SN_X25519_MLKEM768, SCOSSL_LN_X25519_MLKEM768, SYMCRYPT_MLKEM_PARAMS_MLKEM768}, - {NID_undef, NULL, SCOSSL_SN_P384_MLKEM1024, SCOSSL_LN_P384_MLKEM1024, SYMCRYPT_MLKEM_PARAMS_MLKEM1024}}; + {NID_undef, SCOSSL_OID_P256_MLKEM768, SCOSSL_SN_P256_MLKEM768, SCOSSL_LN_P256_MLKEM768, SYMCRYPT_MLKEM_PARAMS_MLKEM768}, + {NID_undef, SCOSSL_OID_X25519_MLKEM768, SCOSSL_SN_X25519_MLKEM768, SCOSSL_LN_X25519_MLKEM768, SYMCRYPT_MLKEM_PARAMS_MLKEM768}, + {NID_undef, SCOSSL_OID_P384_MLKEM1024, SCOSSL_SN_P384_MLKEM1024, SCOSSL_LN_P384_MLKEM1024, SYMCRYPT_MLKEM_PARAMS_MLKEM1024}}; typedef struct { diff --git a/SymCryptProvider/src/keyexch/p_scossl_dh.c b/SymCryptProvider/src/keyexch/p_scossl_dh.c index 670df5e..00ab7fe 100644 --- a/SymCryptProvider/src/keyexch/p_scossl_dh.c +++ b/SymCryptProvider/src/keyexch/p_scossl_dh.c @@ -60,6 +60,12 @@ static const OSSL_PARAM p_scossl_dh_ctx_gettable_param_types[] = { OSSL_PARAM_END}; static SCOSSL_STATUS p_scossl_dh_set_ctx_params(_Inout_ SCOSSL_DH_CTX *ctx, _In_ const OSSL_PARAM params[]); +#if OPENSSL_VERSION_MAJOR == 3 && OPENSSL_VERSION_MINOR < 4 +int EVP_MD_xof(const EVP_MD *md) +{ + return md != NULL && ((EVP_MD_get_flags(md) & EVP_MD_FLAG_XOF) != 0); +} +#endif // OPENSSL_VERSION_MAJOR == 3 && OPENSSL_VERSION_MINOR < 4 static SCOSSL_DH_CTX *p_scossl_dh_newctx(_In_ SCOSSL_PROVCTX *provctx) { @@ -323,8 +329,8 @@ static SCOSSL_STATUS p_scossl_dh_derive(_In_ SCOSSL_DH_CTX *ctx, static SCOSSL_STATUS p_scossl_dh_set_ctx_params(_Inout_ SCOSSL_DH_CTX *ctx, _In_ const OSSL_PARAM params[]) { - const char *mdName = NULL; - const char *mdProps = NULL; + char *mdName = NULL; + char *mdProps = NULL; EVP_MD *md = NULL; SCOSSL_STATUS ret = SCOSSL_FAILURE; const OSSL_PARAM *p = NULL; diff --git a/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c b/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c index c3a2f7e..5681b52 100644 --- a/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c +++ b/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c @@ -999,9 +999,11 @@ static SCOSSL_STATUS p_scossl_ecc_keymgmt_export(_In_ SCOSSL_ECC_KEY_CTX *keyCtx goto cleanup; } - if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0 && + keyCtx->initialized) { - if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0 && + SymCryptEckeyHasPrivateKey(keyCtx->key)) { if (!p_scossl_ecc_keymgmt_get_private_key_bn(keyCtx, &bnPrivateKey, &cbPrivateKey) || !OSSL_PARAM_BLD_push_BN_pad(bld, OSSL_PKEY_PARAM_PRIV_KEY, bnPrivateKey, cbPrivateKey)) diff --git a/SymCryptProvider/src/signature/p_scossl_ecdsa_signature.c b/SymCryptProvider/src/signature/p_scossl_ecdsa_signature.c index 117a01c..f455901 100644 --- a/SymCryptProvider/src/signature/p_scossl_ecdsa_signature.c +++ b/SymCryptProvider/src/signature/p_scossl_ecdsa_signature.c @@ -285,7 +285,7 @@ static SCOSSL_STATUS p_scossl_ecdsa_digest_sign_final(_In_ SCOSSL_ECDSA_CTX *ctx _Out_writes_bytes_(*siglen) unsigned char *sig, _Out_ size_t *siglen, size_t sigsize) { BYTE digest[EVP_MAX_MD_SIZE]; - SIZE_T cbDigest = 0; + unsigned int cbDigest = 0; if (ctx->mdctx == NULL) { @@ -310,7 +310,7 @@ static int p_scossl_ecdsa_digest_verify_final(_In_ SCOSSL_ECDSA_CTX *ctx, _In_reads_bytes_(siglen) unsigned char *sig, size_t siglen) { BYTE digest[EVP_MAX_MD_SIZE]; - SIZE_T cbDigest = 0; + unsigned int cbDigest = 0; if (ctx->mdctx == NULL) { @@ -372,6 +372,24 @@ static SCOSSL_STATUS p_scossl_ecdsa_set_ctx_params(_Inout_ SCOSSL_ECDSA_CTX *ctx return SCOSSL_FAILURE; } +#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE + if ((p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE)) != NULL) + { + unsigned int nonce_type; + if (!OSSL_PARAM_get_uint(p, &nonce_type)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return SCOSSL_FAILURE; + } + + if (nonce_type != 0) + { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED); + return SCOSSL_FAILURE; + } + } +#endif + return SCOSSL_SUCCESS; } @@ -406,6 +424,15 @@ static SCOSSL_STATUS p_scossl_ecdsa_get_ctx_params(_In_ SCOSSL_ECDSA_CTX *ctx, _ goto cleanup; } +#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE + if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE)) != NULL && + !OSSL_PARAM_set_uint(p, 0)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + goto cleanup; + } +#endif + if ((p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID)) != NULL) { int cbAid; diff --git a/SymCryptProvider/src/signature/p_scossl_rsa_signature.c b/SymCryptProvider/src/signature/p_scossl_rsa_signature.c index 81f86b8..43d0783 100644 --- a/SymCryptProvider/src/signature/p_scossl_rsa_signature.c +++ b/SymCryptProvider/src/signature/p_scossl_rsa_signature.c @@ -394,7 +394,7 @@ static SCOSSL_STATUS p_scossl_rsa_digest_sign_final(_In_ SCOSSL_RSA_SIGN_CTX *ct { SCOSSL_STATUS ret = SCOSSL_FAILURE; BYTE digest[EVP_MAX_MD_SIZE]; - SIZE_T cbDigest = 0; + unsigned int cbDigest = 0; if (ctx->mdctx == NULL) { @@ -415,7 +415,7 @@ static SCOSSL_STATUS p_scossl_rsa_digest_verify_final(_In_ SCOSSL_RSA_SIGN_CTX * _In_reads_bytes_(siglen) unsigned char *sig, size_t siglen) { BYTE digest[EVP_MAX_MD_SIZE]; - SIZE_T cbDigest = 0; + unsigned int cbDigest = 0; if (ctx->mdctx == NULL) {