From nobody Fri Nov 14 18:06:36 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=1762262073; cv=none; d=zohomail.com; s=zohoarc; b=DmtF53CjuuoR7z/eAEn5njEO6yd36oSQPRlKK54xZk/TOGYSnnrPZPt2gL3FhrX1S6N+HUmTSe9JdKnP3lncToHecBVtW3FlcyIfhYHeDyekeiRyFUDxTqdoX+c05kxsHGV2IQfNMwee6VcTFK9BXKPakUA00nqBDPdBMlPh7b4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1762262073; 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=65LeBGkfIIfi1HTBLnsw67VOKiKIzyfOPCsCx2gtwJI=; b=HEUZjbtZArAILcG2iynE/f2H3DhGQGtUybUs9S0Y3va/2/sOi0uXvehAmhJdHT0JlkTIeAQP58+LIb0yACE7jl01dMbMg2ew46ZcyXM77sfdQ5qtKW5MeAI8GtC4o3IBVyGjrV22aHt3a21g7HEJmMdJQeVhxhaXYjoRYmBlQME= 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 1762262073335140.25449986837964; Tue, 4 Nov 2025 05:14:33 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vGGrQ-0002sR-Bu; Tue, 04 Nov 2025 08:14:09 -0500 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 1vGGrK-0002q7-Pa for qemu-devel@nongnu.org; Tue, 04 Nov 2025 08:14:02 -0500 Received: from mta-64-226.siemens.flowmailer.net ([185.136.64.226]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vGGrG-0005VV-Rf for qemu-devel@nongnu.org; Tue, 04 Nov 2025 08:14:02 -0500 Received: by mta-64-226.siemens.flowmailer.net with ESMTPSA id 202511041303533eeb05fe5500020700 for ; Tue, 04 Nov 2025 14:03:53 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=fm1; 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=65LeBGkfIIfi1HTBLnsw67VOKiKIzyfOPCsCx2gtwJI=; b=lkOhyVyDoxDo/Afltpc+RoitISLlz2Nue57uyUsaJzYpRmH1jkYBpdk1tWE2Nb9gRqu4M9 QvmXCaKEGeqyj68J0NVyEtuCoUvs8x4mgGSgnAP9SegECR9VFgFBYkkVzGX/EDSMGS2Ea0CG YfdwFPaefB37dstAyxtYgCv4sawlKibNuBe+CG5N+UCUd1sYdOe9GMim0fOMn/R8++z8doYJ Uthb7+XoC5FjGOx7iIVFn6DfrB3CkEU/1efaBXQSVqr+PDkw0uGL2Zz45tzRsLCozWfWn1V9 dTQW/kgq3kdscBL7Ro5SJqtRBJzyfHUKs3b8sgT792WJqJM5dI8ncWVg==; From: Jan Kiszka To: qemu-devel Cc: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Bin Meng , qemu-block@nongnu.org, Ilias Apalodimas , =?UTF-8?q?Alex=20Benn=C3=A9e?= , =?UTF-8?q?Jan=20L=C3=BCbbe?= , Jerome Forissier Subject: [PATCH v6 4/6] hw/sd/sdcard: Handle RPMB MAC field Date: Tue, 4 Nov 2025 14:03:48 +0100 Message-ID: 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.64.226; envelope-from=fm-294854-202511041303533eeb05fe5500020700-tN64DA@rts-flowmailer.siemens.com; helo=mta-64-226.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=unavailable 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: 1762262078486158500 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. This depends on HMAC support for QCRYPTO_HASH_ALGO_SHA256 which is always available via glib - assert this, just to be safe. Signed-off-by: Jan Kiszka Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/sd/sd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index cee738be11..61754bf108 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 @@ -121,6 +122,7 @@ typedef struct SDProto { #define RPMB_KEY_MAC_LEN 32 #define RPMB_DATA_LEN 256 /* one RPMB block is half a sector */ #define RPMB_NONCE_LEN 16 +#define RPMB_HASH_LEN 284 =20 typedef struct QEMU_PACKED { uint8_t stuff_bytes[RPMB_STUFF_LEN]; @@ -1128,6 +1130,68 @@ static void sd_blk_write(SDState *sd, uint64_t addr,= uint32_t len) } } =20 +static bool rpmb_calc_hmac(SDState *sd, const RPMBDataFrame *frame, + unsigned int num_blocks, uint8_t *mac) +{ + g_autoptr(QCryptoHmac) hmac =3D NULL; + size_t mac_len =3D RPMB_KEY_MAC_LEN; + bool success =3D true; + Error *err =3D NULL; + uint64_t offset; + + 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. + */ + void *buf =3D sd->data; + + assert(RPMB_HASH_LEN <=3D sizeof(sd->data)); + + memcpy((uint8_t *)buf + RPMB_DATA_LEN, &frame->data[RPMB_DATA_LEN], + RPMB_HASH_LEN - RPMB_DATA_LEN); + offset =3D lduw_be_p(&frame->address) * RPMB_DATA_LEN + + sd_part_offset(sd); + do { + if (blk_pread(sd->blk, offset, RPMB_DATA_LEN, buf, 0) < 0) { + error_report("sd_blk_read: read error on host side"); + 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; + } + offset +=3D RPMB_DATA_LEN; + } while (--num_blocks > 1); + } + + if (success && + qcrypto_hmac_bytes(hmac, 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); + + return success; +} + static void emmc_rpmb_blk_read(SDState *sd, uint64_t addr, uint32_t len) { uint16_t resp =3D lduw_be_p(&sd->rpmb.result.req_resp); @@ -1151,6 +1215,17 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t= addr, uint32_t len) RPMB_RESULT_READ_FAILURE | (result & RPMB_RESULT_COUTER_EXPIRED)); } + if (sd->multi_blk_cnt =3D=3D 1 && + !rpmb_calc_hmac(sd, &sd->rpmb.result, + lduw_be_p(&sd->rpmb.result.block_count), + sd->rpmb.result.key_mac)) { + memset(sd->rpmb.result.data, 0, sizeof(sd->rpmb.result.data)); + stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_AUTH_FAILURE); + } + } 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)); + stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_AUTH_FAILURE); } memcpy(sd->data, &sd->rpmb.result, sizeof(sd->rpmb.result)); =20 @@ -1162,6 +1237,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 lduw_be_p(&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 */ @@ -1199,6 +1275,11 @@ static void emmc_rpmb_blk_write(SDState *sd, uint64_= t addr, uint32_t len) stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_WRITE_FAILURE); break; } + if (!rpmb_calc_hmac(sd, frame, 1, mac) || + memcmp(frame->key_mac, mac, RPMB_KEY_MAC_LEN) !=3D 0) { + stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_AUTH_FAILURE); + break; + } if (ldl_be_p(&frame->write_counter) !=3D sd->rpmb.write_counter) { stw_be_p(&sd->rpmb.result.result, RPMB_RESULT_COUNTER_FAILURE); break; @@ -3128,6 +3209,8 @@ static void emmc_class_init(ObjectClass *klass, const= void *data) DeviceClass *dc =3D DEVICE_CLASS(klass); SDCardClass *sc =3D SDMMC_COMMON_CLASS(klass); =20 + assert(qcrypto_hmac_supports(QCRYPTO_HASH_ALGO_SHA256)); + dc->desc =3D "eMMC"; dc->realize =3D emmc_realize; device_class_set_props(dc, emmc_properties); --=20 2.51.0