@samitouri / QOSamiQemu / commits / f34a7b3ec6

hw/sd/sdcard: Add support for pre-setting the authentication key

In contrast to real eMMCs, we are not (yet) persisting the full state of the device. This particularly includes the authentication key used for RPMB access, complicating testing of firmware images which do not support initial provisioning of the key. One way to address this would be, e.g., extending the eMMC disk image with a special sector to store further state. A simpler approach is used here: Add another device property that allows to specify the authentication key, bringing up the eMMC as if the key has already been provisioned before. This is how to tell qemu to use the OP-TEE test key: -device emmc,[...],auth-key=D3EB3EC36E334C9F988CE2C0B85954610D2BCF8664844DF2AB56E6C61BB701E4 Or use this for machine-configured eMMCs: -global emmc.auth-key=D3EB3EC36E334C9F988CE2C0B85954610D2BCF8664844DF2AB56E6C61BB701E4 Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Reviewed-by: Jerome Forissier <jerome.forissier@arm.com> Message-ID: <9fab19ee4c755f9cb2abf55494541fcadff46cbd.1776231967.git.jan.kiszka@siemens.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Jan Kiszka committed Apr 15, 2026 at 07:46 UTC f34a7b3ec6960cf009e9240c65faa2c527e07991
2 files changed +46
docs/system/devices/emmc.rst
+23
@@ -53,3 +53,26 @@ SDHCI controllers while assuming that the firmware needs a boot partitions of
53 -drive file=emmc.img,if=none,format=raw,id=emmc-img
54 -device sdhci-pci
55 -device emmc,drive=emmc-img,boot-partition-size=1048576,rpmb-partition-size=2097152
56 +
57 +RPMB Authentication Key
58 +=======================
59 +
60 +A private shared key is used for authenticating requests of the host to the
61 +RPMB. A real eMMC stores this persistently and permits no reprogramming once it
62 +is set. QEMU emulates key programming but does not persist the key state
63 +across restarts. To emulate the state "key is set", the eMMC can be created
64 +with a user-provided key via the ``auth-key`` property:
65 +
66 +.. code-block:: console
67 +
68 + -device emmc,[...],auth-key=D3EB3EC36E334C9F988CE2C0B85954610D2BCF8664844DF2AB56E6C61BB701E4
69 +
70 +This sets the well-known test key of OP-TEE on emmc device creation. In case an
71 +eMMC is instantiated by the machine model already:
72 +
73 +.. code-block:: console
74 +
75 + -global emmc.auth-key=D3EB3EC36E334C9F988CE2C0B85954610D2BCF8664844DF2AB56E6C61BB701E4
76 +
77 +A key always consists of 32 bytes that have to be encoded as hex numbers,
78 +left-padding with zeros as needed.
hw/sd/sd.c
+23
@@ -205,6 +205,7 @@ struct SDState {
205 QEMUTimer *ocr_power_timer;
206 uint8_t dat_lines;
207 bool cmd_line;
208 + char *preset_auth_key;
209 };
210
211 static void sd_realize(DeviceState *dev, Error **errp);
@@ -3132,6 +3133,27 @@ static void sd_realize(DeviceState *dev, Error **errp)
3133 "The RPMB partition size must be multiples of 128K"
3134 "and not larger than 16384K.\n");
3135 }
3136 + if (sd_is_emmc(sd) && sd->preset_auth_key) {
3137 + if (strlen(sd->preset_auth_key) != 64) {
3138 + error_setg(errp,
3139 + "Authentication key must be 32 bytes long, "
3140 + "encoded hexadecimally");
3141 + return;
3142 + }
3143 +
3144 + char *pos = sd->preset_auth_key;
3145 + unsigned int n;
3146 + for (n = 0; n < RPMB_KEY_MAC_LEN; n++, pos += 2) {
3147 + int chrs;
3148 + if (sscanf(pos, "%02hhx%n", &sd->rpmb.key[n], &chrs) != 1 ||
3149 + chrs != 2) {
3150 + error_setg(errp,
3151 + "Authentication key contains invalid characters");
3152 + return;
3153 + }
3154 + }
3155 + sd->rpmb.key_set = 1;
3156 + }
3157 }
3158
3159 static void emmc_realize(DeviceState *dev, Error **errp)
@@ -3156,6 +3178,7 @@ static const Property emmc_properties[] = {
3178 DEFINE_PROP_UINT64("boot-partition-size", SDState, boot_part_size, 0),
3179 DEFINE_PROP_UINT8("boot-config", SDState, boot_config, 0x0),
3180 DEFINE_PROP_UINT64("rpmb-partition-size", SDState, rpmb_part_size, 0),
3181 + DEFINE_PROP_STRING("auth-key", SDState, preset_auth_key),
3182 };
3183
3184 static void sdmmc_common_class_init(ObjectClass *klass, const void *data)