From nobody Sat Nov 15 05:35:28 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass header.i=jan.kiszka@siemens.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=siemens.com ARC-Seal: i=1; a=rsa-sha256; t=1756020610; cv=none; d=zohomail.com; s=zohoarc; b=bcQNyYZI9mJfvdUG251qM9JMcUpNqlxMJlgYdb8Sh97KivwhC4PBUqOxTxSNgViKESKlB0ECQIiyUh7H32F8nkCjvpbS0UezFAMeP8b2rXZwnK3BKFSCN3vp8OuibFW1Uyjv4Nk3Uy3RUjr62f7NXkeTZqsUs0uM9RYrtKxKvtE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1756020610; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=E/UaUmCNNfxda8g655r57Chd4oQH6RUgHLfZO5tpmo0=; b=SzkfOf46Z9IqAKc2dOtq+zk9EtyGj3DnG6wHvaMC9O/xoCU117dmmOZ2O3CSkljRd0cngNejTrMBS7heItp5mJJ12mqhN2868ykpC3fYvd+pOTy38v3gbiKX6/0l3uzMhVsrPeDmBRGybTYgsVZ4lMf7efDVjy3juEtP+CszHwE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=jan.kiszka@siemens.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1756020610528859.2070716642506; Sun, 24 Aug 2025 00:30:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uq59r-0006RH-5D; Sun, 24 Aug 2025 03:28:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uq59p-0006Pd-72 for qemu-devel@nongnu.org; Sun, 24 Aug 2025 03:28:53 -0400 Received: from mta-65-227.siemens.flowmailer.net ([185.136.65.227]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uq59k-0005N5-KH for qemu-devel@nongnu.org; Sun, 24 Aug 2025 03:28:52 -0400 Received: by mta-65-227.siemens.flowmailer.net with ESMTPSA id 2025082407184384f1672652338a15ec for ; Sun, 24 Aug 2025 09:18:43 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm2; d=siemens.com; i=jan.kiszka@siemens.com; h=Date:From:Subject:To:Message-ID:MIME-Version:Content-Type:Content-Transfer-Encoding:Cc:References:In-Reply-To; bh=E/UaUmCNNfxda8g655r57Chd4oQH6RUgHLfZO5tpmo0=; b=F2S7W+cKil2wQSMhzEokdB4ol8gmEJwA5C0vsEqSHPFNrr0DwwjHTihjLfkhaQqY19NTZZ MqJGpxUU+/K2VMXeuKZFjYpx32vSNQwsM64OO0d0A+P8zeMTZ2bxTzb1wkoAPSuDmXkpgnwo rSsbHWvdDPeMeJjBIthckoDGIz8sWJlyaGIXwtvfk5VhlvDPpqc4h/WQC6ZlWpSJ4Rhlvz3o x6LFPP7kZfV5wvagRyCtSGlprqGjq8N0Fa8rIugNqmPyDGLes1U8iN2eKRUMlqFzJ13yv6NR /Qdr+jtDKjw60muAUFsKWqyDdehuxjsW1NGpFJkl9D8pFBgpGPKQI+eA==; From: Jan Kiszka To: qemu-devel Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Ilias Apalodimas Subject: [PATCH 7/8] hw/sd/sdcard: Handle RPMB MAC field Date: Sun, 24 Aug 2025 09:18:39 +0200 Message-ID: <8ea56ae040ef1037e44fc864c159e2f96f23f059.1756019920.git.jan.kiszka@siemens.com> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Flowmailer-Platform: Siemens Feedback-ID: 519:519-294854:519-21489:flowmailer Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=185.136.65.227; envelope-from=fm-294854-2025082407184384f1672652338a15ec-pYYX9F@rts-flowmailer.siemens.com; helo=mta-65-227.siemens.flowmailer.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity jan.kiszka@siemens.com) X-ZM-MESSAGEID: 1756020611570116600 Content-Type: text/plain; charset="utf-8" From: Jan Kiszka Implement correct setting of the MAC field when passing RPMB frames back to the guest. Also check the MAC on authenticated write requests. As this depends on HMAC support for QCRYPTO_HASH_ALGO_SHA256, only register the eMMC class if that is available. Signed-off-by: Jan Kiszka Tested-by: Jerome Forissier --- hw/sd/sd.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index f9578c6e55..1acf9f5306 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -51,6 +51,7 @@ #include "qemu/module.h" #include "sdmmc-internal.h" #include "trace.h" +#include "crypto/hmac.h" =20 //#define DEBUG_SD 1 =20 @@ -118,6 +119,7 @@ typedef struct SDProto { } SDProto; =20 #define RPMB_KEY_MAC_LEN 32 +#define RPMB_HASH_LEN 284 =20 typedef struct { uint8_t stuff_bytes[196]; @@ -1125,6 +1127,66 @@ static void sd_blk_write(SDState *sd, uint64_t addr,= uint32_t len) } } =20 +static bool rpmb_calc_hmac(SDState *sd, RPMBDataFrame *frame, + unsigned int num_blocks, uint8_t *mac) +{ + size_t mac_len =3D RPMB_KEY_MAC_LEN; + bool success =3D true; + Error *err =3D NULL; + QCryptoHmac *hmac; + uint64_t addr; + + hmac =3D qcrypto_hmac_new(QCRYPTO_HASH_ALGO_SHA256, sd->rpmb_key, + RPMB_KEY_MAC_LEN, &err); + if (!hmac) { + error_report_err(err); + return false; + } + + /* + * This implies a read request because we only support single-block wr= ite + * requests so far. + */ + if (num_blocks > 1) { + /* + * Unfortunately, the underlying crypto libraries do not allow us = to + * migrate an active QCryptoHmac state. Therefore, we have to calc= ulate + * the HMAC in one run. To avoid buffering a complete read sequenc= e in + * SDState, reconstruct all frames except for the last one. + */ + char *buf =3D (char *)sd->data; + + memcpy(buf, frame->data, RPMB_HASH_LEN); + addr =3D be16_to_cpu(frame->address) * 256 + sd_part_offset(sd); + do { + if (blk_pread(sd->blk, addr, 256, buf, 0) < 0) { + fprintf(stderr, "sd_blk_read: read error on host side\n"); + success =3D false; + break; + } + if (qcrypto_hmac_bytes(hmac, buf, RPMB_HASH_LEN, NULL, NULL, + &err) < 0) { + error_report_err(err); + success =3D false; + break; + } + addr +=3D 256; + } while (--num_blocks > 1); + } + + if (success && + qcrypto_hmac_bytes(hmac, (const char*)frame->data, RPMB_HASH_LEN, = &mac, + &mac_len, &err) < 0) { + error_report_err(err); + success =3D false; + } + assert(!success || mac_len =3D=3D RPMB_KEY_MAC_LEN); + + qcrypto_hmac_free(hmac); + + return success; +} + static void emmc_rpmb_blk_read(SDState *sd, uint64_t addr, uint32_t len) { uint16_t resp =3D be16_to_cpu(sd->rpmb_result.req_resp); @@ -1145,6 +1207,17 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t= addr, uint32_t len) memset(sd->rpmb_result.data, 0, sizeof(sd->rpmb_result.data)); sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_READ_FAILUR= E); } + if (sd->multi_blk_cnt =3D=3D 1 && + !rpmb_calc_hmac(sd, &sd->rpmb_result, + be16_to_cpu(sd->rpmb_result.block_count), + sd->rpmb_result.key_mac)) { + memset(sd->rpmb_result.data, 0, sizeof(sd->rpmb_result.data)); + sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_AUTH_FAILUR= E); + } + } else if (!rpmb_calc_hmac(sd, &sd->rpmb_result, 1, + sd->rpmb_result.key_mac)) { + memset(sd->rpmb_result.data, 0, sizeof(sd->rpmb_result.data)); + sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_AUTH_FAILURE); } memcpy(sd->data, &sd->rpmb_result, sizeof(sd->rpmb_result)); =20 @@ -1156,6 +1229,7 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_t= addr, uint32_t len) { RPMBDataFrame *frame =3D (RPMBDataFrame *)sd->data; uint16_t req =3D be16_to_cpu(frame->req_resp); + uint8_t mac[RPMB_KEY_MAC_LEN]; =20 if (req =3D=3D RPMB_REQ_READ_RESULT) { /* just return the current result register */ @@ -1189,6 +1263,11 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_= t addr, uint32_t len) sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_GENERAL_FAI= LURE); break; } + if (!rpmb_calc_hmac(sd, frame, 1, mac) || + memcmp(frame->key_mac, mac, RPMB_KEY_MAC_LEN) !=3D 0) { + sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_AUTH_FAILUR= E); + break; + } if (be32_to_cpu(frame->write_counter) !=3D sd->rpmb_write_counter)= { sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_COUNTER_FAI= LURE); break; @@ -3122,6 +3201,7 @@ static const TypeInfo sd_types[] =3D { .parent =3D TYPE_SD_CARD, .class_init =3D sd_spi_class_init, }, + /* must be last element */ { .name =3D TYPE_EMMC, .parent =3D TYPE_SDMMC_COMMON, @@ -3129,4 +3209,12 @@ static const TypeInfo sd_types[] =3D { }, }; =20 -DEFINE_TYPES(sd_types) +static void sd_register_types(void) +{ + int num =3D ARRAY_SIZE(sd_types); + if (!qcrypto_hmac_supports(QCRYPTO_HASH_ALGO_SHA256)) { + num--; + } + type_register_static_array(sd_types, num); +} +type_init(sd_register_types); --=20 2.43.0