From nobody Fri Nov 14 18:05:59 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=1760703398; cv=none; d=zohomail.com; s=zohoarc; b=e57TSnfgty3CbJRLihO8ri8VgftxApEU11G3DpCsmnjGxwmZ5TL/C8YRAzF7pt9nLG98MajkROZn7U5etCl2EQj+D8oiT7QsPdF6dfUMjKGz1u/a6MrPixQg0eKtbjHA+kRmyEmYotlhXFKqsRShYQR0ZhrpXhw7hG0g0Atdxj4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1760703398; 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=ABLPh8cUmMhP+cUyUzsUus/0P+Zv7IY0ctQ4D2pSp4I=; b=j6xoOYt1dmQwSTh52utPOgteQnjbtHNnDE0zs2VGwEQsIklgt5IWkaYRFxVyh2qJ/+LqjVjUt9gCYXfCzoVykoMWMRqaLbkkfWM1bzPNgEs5ye0hvcj4/PfQa1jK6+RfMNAX3x1dor7FVIr/F3hNYgBjTjMVB/LSA+PVNBY/lZs= 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 1760703398329824.4049908388781; Fri, 17 Oct 2025 05:16:38 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1v9jM6-0005y2-B7; Fri, 17 Oct 2025 08:14:46 -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 1v9jLt-0005rC-Kl for qemu-devel@nongnu.org; Fri, 17 Oct 2025 08:14:34 -0400 Received: from mta-64-225.siemens.flowmailer.net ([185.136.64.225]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1v9jLe-0005Ec-R1 for qemu-devel@nongnu.org; Fri, 17 Oct 2025 08:14:33 -0400 Received: by mta-64-225.siemens.flowmailer.net with ESMTPSA id 20251017120402a2edd07b9700020781 for ; Fri, 17 Oct 2025 14:04:02 +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=ABLPh8cUmMhP+cUyUzsUus/0P+Zv7IY0ctQ4D2pSp4I=; b=hynNs38tq2B0F2uY+Qh9bO+amdW3uLnQd3JI5vBZKqMoVvFjw1dhfDB/QaI3eDwmgcABpx Slt/k/sFUp3Z20TlzW50bnovaKncPBUzyw+kBaCU1H7SSeVMDk6KkvJJxeaN9/i9LasK6lxI LmgmEQHhFz/UwmuajQjsjA/N3tvCwJwSbC5/rDu7LDROQ8bBYHf06nldHQEa6I7Uk5UGN6Sl ieBtxM8ZnwuUh7Cze2l2zgOKyjRsmbp2UYm7rd7FXDqz972q/2bboW/saAOYTjs//aJct3qj uJxS/oRnQoeqzOCML6ofdK34b/geHIjbZ4qTGPGrK6jh1V9OgmhqyJug==; 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 v5 4/6] hw/sd/sdcard: Handle RPMB MAC field Date: Fri, 17 Oct 2025 14:03:56 +0200 Message-ID: <30efd95ad5fc54b6afac9d6a0d260c174a6718d2.1760702638.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.64.225; envelope-from=fm-294854-20251017120402a2edd07b9700020781-WDr9hS@rts-flowmailer.siemens.com; helo=mta-64-225.siemens.flowmailer.net X-Spam_score_int: -23 X-Spam_score: -2.4 X-Spam_bar: -- X-Spam_report: (-2.4 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.272, 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_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_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: 1760703400619154100 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 --- hw/sd/sd.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 918fe9f79f..759e284ac0 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]; @@ -1120,6 +1122,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); @@ -1142,6 +1204,17 @@ static void emmc_rpmb_blk_read(SDState *sd, uint64_t= addr, uint32_t len) sd->rpmb_result.result =3D cpu_to_be16(RPMB_RESULT_READ_FAILUR= E | (result & RPMB_RESULT_COUTER_EXPIRED)); } + 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 @@ -1153,6 +1226,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 */ @@ -1190,6 +1264,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_WRITE_FAILU= RE); 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; @@ -3115,6 +3194,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