From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from PH7PR06CU001.outbound.protection.outlook.com (mail-westus3azon11020134.outbound.protection.outlook.com [52.101.201.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F0AA48F840; Tue, 25 Aug 2026 22:15:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.201.134 ARC-Seal:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787696163; cv=fail; b=Q+Q/M1etTGJPLVPIlc93ohrNVSkMjucqsFtkFZgE1aP+UgDUSAI/DxpmQkdEV/eQrT0bKz2OjrRVE4yC6LH2usFaHJrCBCR9Gq9I+eVfVFXF9unZzxDHSnAag4v6mFWMuAeex/Li8Ec9CQCEs6SEC/kX/Z760gw5579RkSyee7E= ARC-Message-Signature:i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787696163; c=relaxed/simple; bh=Eruvy+s7UbKa7uC4VgtjDY4N1dOckrGKTqmvGRS7yNc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cz1HLf/OunXtCFpFcT6wVia6EW41WRdjRsV696BjLR0ZpmU6kAnRAwGsX/B6Ceg9Ev4AG/HlhYOz5bzpB8vHnPFRQpnRnQ/vYUtmz2tkpyXv+YUjWdEFfN6mb5saJNB5jkU1Fwxvl70Y2EdaiOJ5TN1KFpC/dROcpDqukAf5Udo= ARC-Authentication-Results:i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=rambus.com; spf=fail smtp.mailfrom=rambus.com; dkim=pass (2048-bit key) header.d=rambus.com header.i=@rambus.com header.b=5iLi+V63; arc=fail smtp.client-ip=52.101.201.134 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=rambus.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=rambus.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=rambus.com header.i=@rambus.com header.b="5iLi+V63" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=KyFHlXjkOg1o+8XMsE7Oiu10+eM6jpO9KUo1r+Md8EGj6rTB1ahDjokF3G05azVseorc7duqfLJHi0061KfFdSQeW+e1/t+hCO7k1tLDoAJ8OIRiX3JEbq7i1L3o8jgaCA0SmAUzvNnpepBCSiYDjYpcbdXxJfn0Nd6xJhmb6uADA65ppzPifd4MWxVSUleVRAjAgAoG2tJF0vKphhsp6ulzfTSPipy+rws08IO1T49mew1geHlc0ewZ3rU9SUUcFDtKdsM3P88pTCiHbb6jx1fT5HKipOC9gmSE7e677lhwESfFDGR6FD+rDbDp1ZVSVJFePb5/pMzhUxmY0d/Kzw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=HjnrufPkplZwvK9t8i5UWR+pVfjnM56rXoAebULAjDY=; b=LO06juA03mPVR1ApPf4ODHGkuIiS2PJdHbr0Pv/OoJotT6uhbHzL4oWQNtXO+Dauf8PaJjFsjPDWZfooGYEwwAysdp6znHvtTyJzgPgAiDeKm2FMZeEW3bZ6+l42bZbzE62R45NKAP3tS1jooNwNr+oAWGlGwmda39giZa4A80kM4ED77Bc4LranUb9CxZI/wfNRZ6PncCP9parT+ebGGvM/LOqAxc8uDclS2fX4jS9Fe6dfeQRiJ6JepBTGNfq1GNFw8h13HfjhPFqPEEk421hwBnFsbcNJnuqdwWIGtTtdHr+bIW8ZAW64y0boYKF/PDawuVWmnL+tTDK8FKw2dg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 192.86.86.210) smtp.rcpttodomain=cryptography.com smtp.mailfrom=rambus.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=rambus.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rambus.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=HjnrufPkplZwvK9t8i5UWR+pVfjnM56rXoAebULAjDY=; b=5iLi+V63MwSGkeZ5PYc2Dz5kAlIDwnP4JQ6OZ4IpTOX4me2W9fDbGIoaJpTBHPZpfufUkueEtJTYp5hUs4H5Pbbaf+4VQru08jQ6KfMe6F3mYmh84miPJtoKxrZv0T0bTF81/LOc3qMfCujCGo/9UTsaYOGrchgxPbMTeq3m4kwWvGinh4nT5C8KWrPWpC8UDGvl7h2VRH1S5tJQmqVVgPgLlgP+YSlBfiDEe6mxpjrrT7vdyCQdC4L8u4B4a/PtPVf5bXpjmMyxrKMAV7Ax4fYtjgcVHvp2jMSd/L5lQ18CvOvyJuhDRS4Lp7ZXqMpYSAVXrUlWVXL+jhEcuTiK1A== Received: from BY3PR05CA0052.namprd05.prod.outlook.com (2603:10b6:a03:39b::27) by CH8PR04MB994693.namprd04.prod.outlook.com (2603:10b6:610:373::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.6; Tue, 25 Aug 2026 22:15:54 +0000 Received: from BY1PEPF0001AE18.namprd04.prod.outlook.com (2603:10b6:a03:39b:cafe::77) by BY3PR05CA0052.outlook.office365.com (2603:10b6:a03:39b::27) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.360.7 via Frontend Transport; Tue, 25 Aug 2026 22:15:54 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 192.86.86.210) smtp.mailfrom=rambus.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=rambus.com; Received-SPF: Pass (protection.outlook.com: domain of rambus.com designates 192.86.86.210 as permitted sender) receiver=protection.outlook.com; client-ip=192.86.86.210; helo=hqxsv-psmtppxy01.rambus.com; pr=C Received: from hqxsv-psmtppxy01.rambus.com (192.86.86.210) by BY1PEPF0001AE18.mail.protection.outlook.com (10.167.242.100) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.360.3 via Frontend Transport; Tue, 25 Aug 2026 22:15:53 +0000 Received: from hqxsv-cmdev3-aousherovitch.rambus.com (hqn-lb-int-float.rambus.com [10.12.20.20]) by hqxsv-psmtppxy01.rambus.com (Postfix) with ESMTP id AC16B1801771; Tue, 25 Aug 2026 18:15:51 -0400 (EDT) From: Alex Ousherovitch To: Albert Ou , Alex Ousherovitch , Conor Dooley , "David S. Miller" , Herbert Xu , Jonathan Corbet , Krzysztof Kozlowski , Palmer Dabbelt , Paul Walmsley , Rob Herring , Saravanakrishnan Krishnamoorthy , Shuah Khan Cc: Alexandre Ghiti , devicetree@vger.kernel.org, Joel Wittenauer , linux-api@vger.kernel.org, linux-crypto@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-riscv@lists.infradead.org, Shuah Khan , Thi Nguyen Subject: [PATCH v4 17/19] Documentation: ioctl: add CMH ioctl documentation and register 'J' Date: Tue, 25 Aug 2026 15:15:36 -0700 Message-ID: <20260825221539.255951-18-aousherovitch@rambus.com> X-Mailer: git-send-email 2.43.7 In-Reply-To: <20260825221539.255951-1-aousherovitch@rambus.com> References: <20260825221539.255951-1-aousherovitch@rambus.com> Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BY1PEPF0001AE18:EE_|CH8PR04MB994693:EE_ Content-Type: text/plain X-MS-Office365-Filtering-Correlation-Id: bd700058-557a-43c0-005d-08df02f66dd0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|82310400026|1800799024|23010399003|376014|36860700016|921020|22082099003|18002099003|3023799007|56012099006|11063799006|6133799003|10067099003; X-Microsoft-Antispam-Message-Info: 6AaGrEi7FSQC8WJLZesyOxMyvMhSTm6leSP6Z1oxjWun/frHjtSXXQKhvmrvbHkc8DyF/uHqv0eRA7YPyv/c9ohvIxy79oR+SqJF4eKJU6szlXOd5I7T7tllR/385VGwjmA9m4Owuo41WFFZfLrsvx0HkZc4DeeyuBFwUpLNFQY5QKrkVXwzHeZbV+DacNK0y1rgnxSobBq6utzoN3+0xUSvFJ1y+SBno1xJRHiYvrfyORYVlVbIIHrkC9/ydalDF7o5wn5NH5WwRGfbWjBtL1mEcDEyYBtTJ8AhylLrFtaxHZ4S9my1HsJbNe9MPXSYpwV133SeLIGSSSNGoju8HFISJmo6SlY/XpqhUgMIsDmWmhVNtGouKTYx0XfryKXvyDDScjjfNPKcgdtwjN40eSdPoqpRv5VKS2yDF0DXI+sxvAQ8GgDPeKrZdzrY9H87bf7B1+ZHZLv4pD7FfW2tIhyN8qxEzn4qburPVxHUexGQ1+ZlwK8XOsDiptQbKJ6wb2nRpIxnnFFzXeLw6qe1kWTgZAq1kLFqOF6EzyjHxbHQqD4XtzTO9F1yxc4ODmuZ78SnlianCWIUC84/w5Y6OZcNWUUaJVdlzTFvaZC0ZJtsrLuw037TKB6U4gaC2m6OVkZlEqa2cDX6/RCozu/atXeTDV8GqocfJYCvSNXMcw7LwI8QIN9rCVvFxbaPT/JJFo9l/AOmJD3XdqeAhCdLAushFPR9DDNCKKInAX2zJaFlt/5WQQTC5ht3H0qYfR67 X-Forefront-Antispam-Report: CIP:192.86.86.210;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:hqxsv-psmtppxy01.rambus.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(7416014)(82310400026)(1800799024)(23010399003)(376014)(36860700016)(921020)(22082099003)(18002099003)(3023799007)(56012099006)(11063799006)(6133799003)(10067099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 8jO5lWzziuzPvVfGE4GxhMo5tSTgg8GiCKDfydp4fBFVYviv7SGiNxm8gpdm9AgiGEBzK0MpYZBtcSYj6lIdSJlKi890GFhfDB5qN/ZG9P1SxImV7l9jKT/RP5b6ycCtWENLzsKH3X6jP1EjDGu0rQSBi0ESy86sn0Z8DhfXQ/Sz7fYxOlFWkqCQwB2Snkk9DcK/zjD51d2/E/IHY36yRwSQmHPt/HdJ+wbgTuWcstBCkMTglScNR/p+UlPZZmGc6UclzZsUEDRD0+orgPLK4wEhdV4mcB+CJHCuOGReUFWvG5/oqmVrX5nWD8IxzH3mYtbWfb3RhhFoUA5ikMyn78QSByd+IUW7wyCRJJC2bx5DIBUzUKLHW80LG/UFGFr88pqLK8PWv16F6U/Q/NvNV2IDYnANKo058blDaJQpQcHzjmQnrQYVZ3jjHkW9T/FO X-OriginatorOrg: rambus.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Aug 2026 22:15:53.6999 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: bd700058-557a-43c0-005d-08df02f66dd0 X-MS-Exchange-CrossTenant-Id: bd0ba799-c2b9-413c-9c56-5d1731c4827c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=bd0ba799-c2b9-413c-9c56-5d1731c4827c;Ip=[192.86.86.210];Helo=[hqxsv-psmtppxy01.rambus.com] X-MS-Exchange-CrossTenant-AuthSource: BY1PEPF0001AE18.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH8PR04MB994693 Add Documentation/userspace-api/ioctl/cmh_mgmt.rst documenting the ioctl commands on the /dev/cmh_mgmt misc device for the Rambus CryptoManager Hub (CMH) hardware crypto accelerator driver. Covers key management, KIC key derivation, PKE (RSA, ECDSA, ECDH, EdDSA), PQC (ML-KEM, ML-DSA, SLH-DSA), SM2, EAC, and DRBG. Link the page into the userspace-api/ioctl index toctree. Register ioctl magic number 'J' (0x4A) in ioctl-number.rst. The driver uses ioctls 0x01-0x40. Signed-off-by: Alex Ousherovitch Co-developed-by: Saravanakrishnan Krishnamoorthy Signed-off-by: Saravanakrishnan Krishnamoorthy --- .../userspace-api/ioctl/cmh_mgmt.rst | 1292 +++++++++++++++++ Documentation/userspace-api/ioctl/index.rst | 1 + .../userspace-api/ioctl/ioctl-number.rst | 1 + 3 files changed, 1294 insertions(+) create mode 100644 Documentation/userspace-api/ioctl/cmh_mgmt.rst diff --git a/Documentation/userspace-api/ioctl/cmh_mgmt.rst b/Documentation/userspace-api/ioctl/cmh_mgmt.rst new file mode 100644 index 000000000000..c02bac128787 --- /dev/null +++ b/Documentation/userspace-api/ioctl/cmh_mgmt.rst @@ -0,0 +1,1292 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================= +CMH Key Management ioctl Interface (cmh_mgmt) +============================================= + +:Author: Cryptography Research, Inc. (CRI) +:Maintainer: linux-crypto@vger.kernel.org + +Introduction +============ + +The ``/dev/cmh_mgmt`` character device provides user-space access to key +management, key derivation, public-key, and post-quantum cryptographic +operations on the CryptoManager Hub (CMH) hardware accelerator. + +The device is created by the ``cmh`` kernel module as a ``misc_device``. +All operations are synchronous -- the ioctl blocks until the hardware +completes. Opening the device requires ``CAP_SYS_ADMIN``. + +All ioctl argument structures are versioned: user space sets the +``version`` field to ``CMH_MGMT_V1`` (currently 1). This allows the +driver to extend structures in the future without breaking the ABI. + +Data types and ioctl numbers are defined in +````. The ioctl type letter is ``'J'`` +(0x4A). + +Error Handling +============== + +Unless otherwise noted, all ioctls return 0 on success and a negative +errno on failure. Common error codes: + +========== ============================================================= +``EINVAL`` Invalid ``version`` field, unsupported parameter, or + out-of-range length. +``EFAULT`` Failed to copy data to/from user space. +``ENOMEM`` Kernel memory allocation failed. +``EIO`` Hardware returned an error (eSW command failure). +``ENOENT`` Key not found (``KEY_FIND``, ``KEY_LIST``). +========== ============================================================= + +Datastore Concepts +================== + +The CMH hardware maintains an embedded datastore managed by the eSW +firmware. Objects in the datastore are identified by a 64-bit reference +(``ref``) and optionally by a 64-bit Content ID (``cid``). + +Two storage classes exist: + +**Temporary (SYS_REF_TEMP)** + Lifetime is scoped to a single mailbox slot. The eSW firmware + reclaims the object when the slot is reused. Used for raw-key + provisioning via ``KEY_NEW`` + ``KEY_WRITE``. + +**Persistent (SYS_REF_PERSIST)** + Survives across mailbox slots. Requires explicit deletion via + ``KEY_DELETE``. Identified by CID; resolved to a per-mailbox ref + via ``KEY_FIND``. + +Mailbox Dispatch +================ + +All ``/dev/cmh_mgmt`` ioctls are submitted on a single management +mailbox. This is a structural requirement of the eSW datastore model, +not a tunable: + +* Datastore access control is **per-mailbox**. ``KEY_NEW`` grants the + creating mailbox read/write/execute access; other mailboxes have none + until granted. The returned 64-bit ``ref`` encodes a randomised + offset and does **not** carry the owning mailbox, so an operation that + receives only a ``ref`` (``KEY_GRANT``, ``KEY_READ``, ``KEY_DELETE``, + ``DS_EXPORT``) cannot itself determine which mailbox owns the object. + Using one fixed management mailbox guarantees that a key's create, + modify, grant, read and hardware-held-key compute steps all share the + mailbox that holds its access rights, without exposing mailbox + identity in the UABI. User space may still widen a key's access to + additional mailboxes via ``KEY_GRANT``. + +* The eSW ``SYS_REF_TEMP`` scratch store is per-mailbox and persists + across ioctl calls, so a multi-step flow that derives into + ``SYS_REF_TEMP`` (for example a ``KIC_*`` derivation) and later + consumes it (``DS_EXPORT`` with ``wrap_key = SYS_REF_TEMP``) requires + both calls to use the same mailbox. + +Per-mailbox ``rambus,cores`` device-tree affinity applies to the *stateless* +in-kernel crypto API path, which carries no datastore state between +requests and is balanced across mailboxes by the driver. + +Key Types +========= + +The ``ds_type`` field in ``KEY_NEW`` and ``KEY_WRITE`` selects the +datastore object type. Values are defined as ``CMH_DS_*`` constants: + +================================= ===== ============================== +Constant Value Description +================================= ===== ============================== +``CMH_DS_RAW_VALUE`` 1 Raw byte array +``CMH_DS_AES_KEY`` 2 AES key (128/192/256-bit) +``CMH_DS_AES_XTS_KEY`` 3 AES-XTS key (256/512-bit) +``CMH_DS_HMAC_KEY`` 4 HMAC key +``CMH_DS_KMAC_KEY`` 5 KMAC key +``CMH_DS_SM4_KEY`` 6 SM4 key (128-bit) +``CMH_DS_CHACHA20_KEY`` 7 ChaCha20 key (256-bit) +``CMH_DS_RSA_PRIV_KEY`` 10 RSA private key +``CMH_DS_RSA_PUB_KEY`` 11 RSA public key +``CMH_DS_RSA_CRT_KEY`` 12 RSA CRT private key +``CMH_DS_ECDSA_PRIV_KEY`` 13 ECDSA private key +``CMH_DS_ECDSA_PUB_KEY`` 14 ECDSA public key +``CMH_DS_ECDH_PRIV_KEY`` 15 ECDH private key +``CMH_DS_EDDSA_PRIV_KEY`` 16 EdDSA private key +``CMH_DS_SHARED_SECRET`` 17 Shared secret +``CMH_DS_SM2_PRIV_KEY`` 18 SM2 private key +``CMH_DS_ML_KEM_DK`` 20 ML-KEM decapsulation key +``CMH_DS_ML_DSA_SK`` 21 ML-DSA secret key +``CMH_DS_SLHDSA_SK`` 25 SLH-DSA secret key +================================= ===== ============================== + +Key Flags +========= + +The ``flags`` field in ``KEY_NEW`` and ``KEY_WRITE`` is a bitmask: + +================== =========== ======================================== +Flag Bit Description +================== =========== ======================================== +``CMH_FLAG_PT`` 16 Key can be read as plaintext +``CMH_FLAG_XC`` 17 Key can be exported over XC bus +``CMH_FLAG_SCA`` 18 SCA key stored in 2 shares +================== =========== ======================================== + +Elliptic Curve IDs +================== + +Curve identifiers for PKE operations (``curve`` field): + +========================== ===== +Constant Value +========================== ===== +``CMH_CURVE_P192`` 0x01 +``CMH_CURVE_P224`` 0x02 +``CMH_CURVE_P256`` 0x03 +``CMH_CURVE_P384`` 0x04 +``CMH_CURVE_P521`` 0x05 +``CMH_CURVE_SECP256K1`` 0x07 +``CMH_CURVE_BP192R1`` 0x11 +``CMH_CURVE_BP224R1`` 0x12 +``CMH_CURVE_BP256R1`` 0x13 +``CMH_CURVE_BP320R1`` 0x14 +``CMH_CURVE_BP384R1`` 0x15 +``CMH_CURVE_BP512R1`` 0x16 +``CMH_CURVE_SM2`` 0x18 +``CMH_CURVE_25519`` 0x21 +``CMH_CURVE_448`` 0x22 +========================== ===== + +Key Management ioctls +===================== + +CMH_IOCTL_KEY_NEW +----------------- + +Create a new empty datastore object. + +:Direction: ``_IOWR`` +:Number: 0x01 +:Argument: ``struct cmh_ioctl_key_new`` + +:: + + struct cmh_ioctl_key_new { + __u32 version; /* must be CMH_MGMT_V1 */ + __u32 ds_type; /* CMH_DS_* key type */ + __u32 len; /* key length in bytes */ + __u32 flags; /* CMH_FLAG_* */ + __u64 cid; /* caller ID (name) for the key */ + __u64 ref; /* [out] key reference */ + }; + +The returned ``ref`` is used in subsequent ``KEY_WRITE``, ``KEY_READ``, +and crypto operation ioctls. + +CMH_IOCTL_KEY_NEW_RANDOM +------------------------ + +Create a new datastore object filled with hardware-generated random data. + +:Direction: ``_IOWR`` +:Number: 0x0B +:Argument: ``struct cmh_ioctl_key_new`` + +Same structure as ``KEY_NEW``. The hardware DRBG fills the object with +``len`` random bytes. + +CMH_IOCTL_KEY_WRITE +------------------- + +Write key material into a previously created datastore object. + +:Direction: ``_IOW`` +:Number: 0x02 +:Argument: ``struct cmh_ioctl_key_write`` + +:: + + struct cmh_ioctl_key_write { + __u32 version; + __u32 len; /* key data length */ + __u32 ds_type; /* CMH_DS_* key type */ + __u32 flags; /* CMH_FLAG_* */ + __u64 ref; /* key reference from KEY_NEW */ + __u64 wrap_key; /* wrapping key ref (CMH_REF_NONE = plaintext) */ + __u64 data; /* user-space pointer to key material */ + }; + +If ``wrap_key`` is ``CMH_REF_NONE`` (0), key material is written in +plaintext. Otherwise, the data is unwrapped using the specified +wrapping key. + +CMH_IOCTL_KEY_READ +------------------ + +Read key material from a datastore object. + +:Direction: ``_IOWR`` +:Number: 0x03 +:Argument: ``struct cmh_ioctl_key_read`` + +:: + + struct cmh_ioctl_key_read { + __u32 version; + __u32 len; /* buffer length */ + __u64 ref; /* key reference */ + __u64 wrap_key; /* wrapping key ref (CMH_REF_NONE = plaintext) */ + __u64 data; /* user-space pointer to output buffer */ + __u32 out_len; /* [out] actual bytes written */ + __u32 __reserved; + }; + +Plaintext reads require the ``CMH_FLAG_PT`` attribute on the key. +The eSW prepends a 16-byte header (``CMH_SYS_WRAP_HDR_SIZE``) even +for plaintext reads; the output buffer must accommodate this. The +output overhead is ``CMH_DS_EXPORT_OVERHEAD_PLAIN`` (16 bytes) for +plaintext reads and ``CMH_DS_EXPORT_OVERHEAD_WRAPPED`` (48 bytes: +16-byte header + 16-byte nonce + 16-byte tag) for wrapped reads. + +CMH_IOCTL_KEY_FIND +------------------ + +Resolve a Content ID to a datastore reference. + +:Direction: ``_IOWR`` +:Number: 0x04 +:Argument: ``struct cmh_ioctl_key_find`` + +:: + + struct cmh_ioctl_key_find { + __u32 version; + __u32 __reserved; + __u64 cid; /* caller ID to search for */ + __u64 ref; /* [out] resolved key reference */ + __u32 len; /* [out] key length */ + __u32 type; /* [out] key type */ + }; + +Returns ``-ENOENT`` if no object with the given CID exists. + +CMH_IOCTL_KEY_LIST +------------------ + +Iterate datastore objects. + +:Direction: ``_IOWR`` +:Number: 0x0E +:Argument: ``struct cmh_ioctl_key_list`` + +:: + + struct cmh_ioctl_key_list { + __u32 version; + __u32 __reserved; + __u64 start_ref; /* starting DS reference (0 = first) */ + __u64 ref; /* [out] object reference */ + __u64 cid; /* [out] caller ID */ + __u32 len; /* [out] object length */ + __u32 type; /* [out] object type */ + }; + +Pass ``start_ref=0`` to begin from the first object. On return, pass +the returned ``ref`` as ``start_ref`` in the next call. Iteration ends +when ``ref == 0``. + +CMH_IOCTL_KEY_GRANT +------------------- + +Set per-mailbox access permissions on a datastore object. + +:Direction: ``_IOW`` +:Number: 0x05 +:Argument: ``struct cmh_ioctl_key_grant`` + +:: + + struct cmh_ioctl_key_grant { + __u32 version; + __u32 __reserved; + __u64 ref; /* key reference */ + __u64 read; /* per-MBX read permission bitfield */ + __u64 write; /* per-MBX write permission bitfield */ + __u64 execute; /* per-MBX execute permission bitfield */ + }; + +CMH_IOCTL_KEY_DELETE +-------------------- + +Delete a datastore object (persistent keys only). + +:Direction: ``_IOW`` +:Number: 0x06 +:Argument: ``struct cmh_ioctl_key_grant`` + +Uses the same structure as ``KEY_GRANT``; only the ``ref`` field is +used. + +Datastore Export/Import ioctls +============================== + +CMH_IOCTL_DS_EXPORT +------------------- + +Export the entire datastore as an encrypted blob. + +:Direction: ``_IOWR`` +:Number: 0x07 +:Argument: ``struct cmh_ioctl_ds_export`` + +:: + + struct cmh_ioctl_ds_export { + __u32 version; + __u32 len; /* buffer length */ + __u64 cid; /* caller ID for response tagging */ + __u64 wrap_key; /* wrapping key ref (CMH_REF_NONE = plaintext) */ + __u64 data; /* user-space pointer to output buffer */ + __u32 out_len; /* [out] actual bytes written */ + __u32 __reserved; + }; + +CMH_IOCTL_DS_IMPORT +------------------- + +Import a previously exported datastore blob. + +:Direction: ``_IOW`` +:Number: 0x08 +:Argument: ``struct cmh_ioctl_ds_import`` + +:: + + struct cmh_ioctl_ds_import { + __u32 version; + __u32 len; /* blob length */ + __u64 wrap_key; /* wrapping key ref (CMH_REF_NONE = plaintext) */ + __u64 data; /* user-space pointer to import blob */ + }; + +Key Derivation ioctls (KIC) +=========================== + +The Key Initialization Core (KIC) provides hardware key derivation from +OTP-provisioned base keys. Up to 8 base keys are available +(``CMH_KIC_KEY1`` through ``CMH_KIC_KEY8``). + +CMH_IOCTL_KIC_HKDF1 +-------------------- + +HKDF-based key derivation (single-step, label only). + +:Direction: ``_IOWR`` +:Number: 0x09 +:Argument: ``struct cmh_ioctl_kic_hkdf1`` + +:: + + struct cmh_ioctl_kic_hkdf1 { + __u32 version; + __u32 key_len; /* output key length */ + __u64 base_key; /* KIC base key reference */ + __u64 cid; /* CID for the new DS entry */ + __u64 label; /* user-space pointer to label data */ + __u32 label_len; /* label length in bytes */ + __u32 flags; /* CMH_KIC_FLAG_* */ + __u64 ref; /* [out] derived key reference */ + }; + +If ``CMH_KIC_FLAG_TEMP`` is set, the result is stored in the temporary +datastore (not persistent). + +CMH_IOCTL_KIC_HKDF2 +-------------------- + +HKDF-based key derivation (two-step, with salt key). + +:Direction: ``_IOWR`` +:Number: 0x0A +:Argument: ``struct cmh_ioctl_kic_hkdf2`` + +:: + + struct cmh_ioctl_kic_hkdf2 { + __u32 version; + __u32 key_len; + __u64 base_key; + __u64 salt_key; /* salt key reference (CMH_REF_NONE = no salt) */ + __u64 cid; + __u64 label; + __u32 label_len; + __u32 flags; + __u64 ref; /* [out] derived key reference */ + }; + +CMH_IOCTL_KIC_AES_CMAC_KDF +--------------------------- + +AES-CMAC-based key derivation (NIST SP 800-108). + +:Direction: ``_IOWR`` +:Number: 0x0C +:Argument: ``struct cmh_ioctl_kic_aes_cmac_kdf`` + +:: + + struct cmh_ioctl_kic_aes_cmac_kdf { + __u32 version; + __u32 key_len; /* base & output key length (must be 32) */ + __u64 base_key; + __u64 cid; + __u64 label; + __u32 label_len; + __u32 flags; + __u64 ref; /* [out] derived key reference */ + }; + +CMH_IOCTL_KIC_DKEK_DERIVE +-------------------------- + +Derive a Device Key Encryption Key (DKEK) for secure key export. + +:Direction: ``_IOWR`` +:Number: 0x0D +:Argument: ``struct cmh_ioctl_kic_dkek_derive`` + +:: + + struct cmh_ioctl_kic_dkek_derive { + __u32 version; + __u32 host_id; /* target host ID (0 = caller's own) */ + __u64 base_key; + __u64 cid; + __u64 metadata; /* user-space pointer to metadata */ + __u32 metadata_len; + __u32 flags; + __u64 ref; /* [out] derived KEK reference */ + }; + +PKE (Public Key Engine) ioctls +============================== + +RSA Operations +-------------- + +CMH_IOCTL_PKE_RSA_ENC +~~~~~~~~~~~~~~~~~~~~~~ + +RSA public-key encryption. + +:Direction: ``_IOWR`` +:Number: 0x10 +:Argument: ``struct cmh_ioctl_pke_rsa_enc`` + +:: + + struct cmh_ioctl_pke_rsa_enc { + __u32 version; + __u32 bits; /* RSA key size in bits (512-4096) */ + __u64 e; /* user-space pointer to public exponent */ + __u32 e_len; /* exponent length in bytes */ + __u32 __reserved; + __u64 n; /* user-space pointer to modulus */ + __u64 input; /* user-space pointer to input data */ + __u64 output; /* user-space pointer to output buffer */ + }; + +The public key (e, n) is passed as raw user-space buffers. + +CMH_IOCTL_PKE_RSA_DEC +~~~~~~~~~~~~~~~~~~~~~~ + +RSA private-key decryption using a datastore key reference. + +:Direction: ``_IOWR`` +:Number: 0x11 +:Argument: ``struct cmh_ioctl_pke_rsa_dec`` + +:: + + struct cmh_ioctl_pke_rsa_dec { + __u32 version; + __u32 bits; + __u64 e; /* public exponent */ + __u32 e_len; + __u32 __reserved; + __u64 n; /* modulus */ + __u64 input; /* ciphertext */ + __u64 output; /* plaintext output */ + __u64 key_ref; /* private key DS reference */ + }; + +CMH_IOCTL_PKE_RSA_CRT_DEC +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +RSA CRT private-key decryption (faster, uses CRT key format). + +:Direction: ``_IOWR`` +:Number: 0x12 +:Argument: ``struct cmh_ioctl_pke_rsa_crt_dec`` + +:: + + struct cmh_ioctl_pke_rsa_crt_dec { + __u32 version; + __u32 bits; + __u64 e; + __u32 e_len; + __u32 __reserved; + __u64 n; + __u64 input; + __u64 output; + __u64 crt_ref; /* CRT key DS reference */ + }; + +CMH_IOCTL_PKE_RSA_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate an RSA key pair in hardware. + +:Direction: ``_IOWR`` +:Number: 0x13 +:Argument: ``struct cmh_ioctl_pke_rsa_keygen`` + +:: + + struct cmh_ioctl_pke_rsa_keygen { + __u32 version; + __u32 bits; /* key size in bits */ + __u64 e; /* user-space pointer to public exponent */ + __u32 e_len; + __u32 flags; /* CMH_FLAG_* */ + __u64 n; /* [out] user-space pointer to modulus buffer */ + __u64 d_cid; /* CID for private key DS entry */ + __u64 d_ref; /* [out] private key reference */ + __u64 crt_cid; /* CID for CRT key DS entry (0 = skip CRT) */ + __u64 crt_ref; /* [out] CRT key reference */ + }; + +Returns private key and optional CRT key as datastore references. +The modulus is written back to user space. + +ECDSA Operations +---------------- + +CMH_IOCTL_PKE_ECDSA_SIGN +~~~~~~~~~~~~~~~~~~~~~~~~~ + +ECDSA signature generation using a datastore private key. + +:Direction: ``_IOWR`` +:Number: 0x14 +:Argument: ``struct cmh_ioctl_pke_ecdsa_sign`` + +:: + + struct cmh_ioctl_pke_ecdsa_sign { + __u32 version; + __u32 curve; /* ABI curve ID (e.g. 0x03 = P-256) */ + __u64 digest; /* user-space pointer to hash digest */ + __u32 digest_len; /* digest length in bytes */ + __u32 __reserved; + __u64 signature; /* [out] user-space pointer to (r,s) */ + __u64 key_ref; /* private key DS reference */ + }; + +CMH_IOCTL_PKE_ECDH +~~~~~~~~~~~~~~~~~~~ + +Compute ECDH shared secret from a peer public key and a datastore +private key. + +:Direction: ``_IOWR`` +:Number: 0x16 +:Argument: ``struct cmh_ioctl_pke_ecdh`` + +:: + + struct cmh_ioctl_pke_ecdh { + __u32 version; + __u32 curve; + __u64 peer_key_x; /* user-space pointer to peer public key X */ + __u64 key_ref; /* private key DS reference */ + __u32 flags; /* reserved, must be 0 */ + __u32 __reserved; + __u64 __reserved2; /* reserved, must be 0 */ + __u64 output; /* [out] raw shared secret */ + }; + +CMH_IOCTL_PKE_ECDH_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Derive a public key from a datastore private key. + +:Direction: ``_IOWR`` +:Number: 0x17 +:Argument: ``struct cmh_ioctl_pke_ecdh_keygen`` + +:: + + struct cmh_ioctl_pke_ecdh_keygen { + __u32 version; + __u32 curve; + __u64 key_ref; /* private key DS reference */ + __u64 public_key_x; /* [out] user-space pointer to public key X */ + }; + +EdDSA Operations +---------------- + +CMH_IOCTL_PKE_EDDSA_SIGN +~~~~~~~~~~~~~~~~~~~~~~~~~ + +EdDSA (Ed25519/Ed448) signature generation. + +:Direction: ``_IOWR`` +:Number: 0x18 +:Argument: ``struct cmh_ioctl_pke_eddsa_sign`` + +:: + + struct cmh_ioctl_pke_eddsa_sign { + __u32 version; + __u32 curve; /* CURVE_25519 or CURVE_448 */ + __u64 digest; /* user-space ptr to message (not digest) */ + __u32 digest_len; + __u32 __reserved; + __u64 signature; /* [out] user-space pointer to signature */ + __u64 key_ref; /* private key DS reference */ + }; + +Note: the ``digest`` field is the full message (pure EdDSA), not a +pre-computed hash. + +CMH_IOCTL_PKE_EDDSA_VERIFY +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +EdDSA signature verification. + +:Direction: ``_IOW`` +:Number: 0x19 +:Argument: ``struct cmh_ioctl_pke_eddsa_verify`` + +:: + + struct cmh_ioctl_pke_eddsa_verify { + __u32 version; + __u32 curve; + __u64 digest; + __u32 digest_len; + __u32 __reserved; + __u64 signature; + __u64 public_key_y; /* user-space pointer to public key Y */ + }; + +EC Key Management +----------------- + +CMH_IOCTL_PKE_EC_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate an EC private key in the hardware datastore. + +:Direction: ``_IOWR`` +:Number: 0x1A +:Argument: ``struct cmh_ioctl_pke_ec_keygen`` + +:: + + struct cmh_ioctl_pke_ec_keygen { + __u32 version; + __u32 curve; + __u32 flags; /* CMH_FLAG_* */ + __u32 __reserved; + __u64 cid; /* CID for the new key DS entry */ + __u64 ref; /* [out] private key reference */ + }; + +CMH_IOCTL_PKE_EC_PUBGEN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Derive the public key from a datastore private key. + +:Direction: ``_IOWR`` +:Number: 0x1B +:Argument: ``struct cmh_ioctl_pke_ec_pubgen`` + +:: + + struct cmh_ioctl_pke_ec_pubgen { + __u32 version; + __u32 curve; + __u64 key_ref; /* private key DS reference */ + __u64 public_key; /* [out] user-space pointer to public key */ + }; + +CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate a 2-share SCA-protected Ed448 private key. + +:Direction: ``_IOWR`` +:Number: 0x1C +:Argument: ``struct cmh_ioctl_pke_eddsa_keygen_sca`` + +:: + + struct cmh_ioctl_pke_eddsa_keygen_sca { + __u32 version; + __u32 curve; /* must be CURVE_448 */ + __u64 key_ref; /* input: normal Ed448 private key DS ref */ + __u64 cid; /* CID for the new SCA key DS entry */ + __u64 sca_ref; /* [out] SCA private key reference */ + }; + +Post-Quantum Cryptography (PQC) ioctls +======================================= + +PQC operations support the following flags in the ``flags`` field: + +============================ ==== ==================================== +Flag Bit Description +============================ ==== ==================================== +``CMH_QSE_FLAG_MASKED`` 0 Use masked (SCA-resistant) HW path +``CMH_QSE_FLAG_DS_REF`` 1 Store key output in DS, return ref +``CMH_QSE_FLAG_HW_RNG`` 2 Use HW RNG for seed/randomness +============================ ==== ==================================== + +ML-KEM (FIPS 203) +----------------- + +CMH_IOCTL_ML_KEM_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate an ML-KEM key pair. + +:Direction: ``_IOWR`` +:Number: 0x20 +:Argument: ``struct cmh_ioctl_ml_kem_keygen`` + +:: + + struct cmh_ioctl_ml_kem_keygen { + __u32 version; + __u32 k; /* security parameter: 2/3/4 */ + __u32 flags; /* CMH_QSE_FLAG_* */ + __u32 __reserved; + __u64 seed; /* user-space pointer to seed (or 0 for HW RNG) */ + __u64 z; /* user-space pointer to z (or 0 for HW RNG) */ + __u64 ek; /* [out] user-space pointer to encapsulation key */ + __u64 dk; /* [out] user-space pointer to decapsulation key, + * or [out] DS ref if CMH_QSE_FLAG_DS_REF */ + __u64 dk_cid; /* CID for DS entry (if DS_REF) */ + __u64 dk_ref; /* [out] dk DS reference (if DS_REF) */ + }; + +Security parameter ``k`` selects the strength: 2 (ML-KEM-512), +3 (ML-KEM-768), or 4 (ML-KEM-1024). + +CMH_IOCTL_ML_KEM_ENC +~~~~~~~~~~~~~~~~~~~~~ + +ML-KEM encapsulation. Produces ciphertext and shared secret. + +:Direction: ``_IOWR`` +:Number: 0x21 +:Argument: ``struct cmh_ioctl_ml_kem_enc`` + +:: + + struct cmh_ioctl_ml_kem_enc { + __u32 version; + __u32 k; + __u32 flags; /* CMH_QSE_FLAG_* */ + __u32 __reserved; + __u64 coin; /* user-space pointer to random coin (or 0) */ + __u64 ek; /* user-space pointer to encapsulation key */ + __u64 ct; /* [out] user-space pointer to ciphertext */ + __u64 ss; /* [out] user-space pointer to shared secret */ + __u64 __reserved2[2]; /* reserved for future use */ + }; + +CMH_IOCTL_ML_KEM_DEC +~~~~~~~~~~~~~~~~~~~~~ + +ML-KEM decapsulation. Recovers shared secret from ciphertext. + +:Direction: ``_IOWR`` +:Number: 0x22 +:Argument: ``struct cmh_ioctl_ml_kem_dec`` + +:: + + struct cmh_ioctl_ml_kem_dec { + __u32 version; + __u32 k; + __u32 flags; /* CMH_QSE_FLAG_* */ + __u32 __reserved; + __u64 ct; /* user-space pointer to ciphertext */ + __u64 dk; /* user-space pointer to dk or DS ref */ + __u64 ss; /* [out] user-space pointer to shared secret */ + __u64 __reserved2[2]; /* reserved for future use */ + }; + +ML-DSA (FIPS 204) +----------------- + +CMH_IOCTL_ML_DSA_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate an ML-DSA key pair. + +:Direction: ``_IOWR`` +:Number: 0x23 +:Argument: ``struct cmh_ioctl_ml_dsa_keygen`` + +:: + + struct cmh_ioctl_ml_dsa_keygen { + __u32 version; + __u32 mode; /* security parameter: 2/3/5 */ + __u32 flags; /* CMH_QSE_FLAG_* */ + __u32 __reserved; + __u64 seed; /* user-space pointer to seed (or 0 for HW RNG) */ + __u64 pk; /* [out] user-space pointer to public key */ + __u64 sk; /* [out] user-space pointer to secret key, + * or [out] DS ref if CMH_QSE_FLAG_DS_REF */ + __u64 sk_cid; /* CID for DS entry (if DS_REF) */ + __u64 sk_ref; /* [out] sk DS reference (if DS_REF) */ + }; + +Security parameter ``mode`` selects the strength: 2 (ML-DSA-44), +3 (ML-DSA-65), or 5 (ML-DSA-87). + +.. note:: + + When ``CMH_QSE_FLAG_DS_REF`` keeps the secret key in the datastore, + the public key returned in ``pk`` is the only copy: there is no + operation to derive the public key from the secret-key reference + for ML-DSA. User space must persist ``pk`` at keygen time. + +CMH_IOCTL_ML_DSA_SIGN +~~~~~~~~~~~~~~~~~~~~~~ + +ML-DSA signature generation. + +:Direction: ``_IOWR`` +:Number: 0x24 +:Argument: ``struct cmh_ioctl_ml_dsa_sign`` + +:: + + struct cmh_ioctl_ml_dsa_sign { + __u32 version; + __u32 mode; + __u32 flags; /* CMH_QSE_FLAG_* */ + __u32 mlen; /* message length in bytes */ + __u64 m; /* user-space pointer to message */ + __u64 sk; /* user-space pointer to sk or DS ref */ + __u64 sig; /* [out] user-space pointer to signature */ + __u64 rnd; /* user-space pointer to randomness (or 0) */ + }; + +If ``mlen`` is set to ``CMH_ML_DSA_MLEN_EXTERNAL_MU`` (0xFFFFFFFF), +the ``m`` pointer is interpreted as a 64-byte pre-hashed mu value +(ExternalMu mode). + +CMH_IOCTL_SLHDSA_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~ + +Generate an SLH-DSA key pair. + +:Direction: ``_IOWR`` +:Number: 0x28 +:Argument: ``struct cmh_ioctl_slhdsa_keygen`` + +:: + + struct cmh_ioctl_slhdsa_keygen { + __u32 version; + __u32 parameter_set; /* HCQ_SLHDSA_SHAKE_128S .. SHA2_256F */ + __u32 flags; /* CMH_QSE_FLAG_DS_REF */ + __u32 __reserved; + __u64 seed; /* user-space pointer to seed */ + __u64 pk; /* [out] user-space pointer to public key */ + __u64 sk; /* [out] user-space pointer to secret key, + * or [out] DS ref if CMH_QSE_FLAG_DS_REF */ + __u64 sk_cid; /* CID for DS entry (if DS_REF) */ + __u64 sk_ref; /* [out] sk DS reference (if DS_REF) */ + }; + +.. note:: + + When ``CMH_QSE_FLAG_DS_REF`` keeps the secret key in the datastore, + the public key returned in ``pk`` is the only copy: there is no + operation to derive the public key from the secret-key reference + for SLH-DSA. User space must persist ``pk`` at keygen time. + +CMH_IOCTL_SLHDSA_SIGN +~~~~~~~~~~~~~~~~~~~~~~ + +SLH-DSA signature generation (pure mode). + +:Direction: ``_IOWR`` +:Number: 0x29 +:Argument: ``struct cmh_ioctl_slhdsa_sign`` + +:: + + struct cmh_ioctl_slhdsa_sign { + __u32 version; + __u32 parameter_set; + __u32 msg_len; + __u32 ctx_len; + __u64 msg; /* user-space pointer to message */ + __u64 ctx; /* user-space pointer to context (or 0) */ + __u64 sk; /* DS ref for secret key */ + __u64 sig; /* [out] user-space pointer to signature */ + __u64 add_random; /* user-space pointer to addl. randomness (or 0) */ + }; + +CMH_IOCTL_SLHDSA_SIGN_PREHASH +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +SLH-DSA pre-hash signature generation. + +:Direction: ``_IOWR`` +:Number: 0x2D +:Argument: ``struct cmh_ioctl_slhdsa_sign_prehash`` + +:: + + struct cmh_ioctl_slhdsa_sign_prehash { + __u32 version; + __u32 parameter_set; + __u32 prehash_algo; /* CMH_SLHDSA_PREHASH_* */ + __u32 digest; /* 0 = raw msg (eSW hashes), 1 = pre-computed */ + __u32 msg_len; + __u32 ctx_len; + __u64 msg; /* user-space pointer to message/digest */ + __u64 ctx; /* user-space pointer to context (or 0) */ + __u64 sk; /* DS ref for secret key */ + __u64 sig; /* [out] user-space pointer to signature */ + __u64 add_random; /* user-space pointer to addl. randomness (or 0) */ + }; + +The ``prehash_algo`` field selects the hash algorithm +(``CMH_SLHDSA_PREHASH_SHA256``, etc.). + +CMH_IOCTL_SM2_ENC_POINT +~~~~~~~~~~~~~~~~~~~~~~~~ + +:Direction: ``_IOWR`` +:Number: 0x33 +:Argument: ``struct cmh_ioctl_sm2_enc_point`` + +:: + + struct cmh_ioctl_sm2_enc_point { + __u32 version; + __u32 nonce_len; /* 0 = HW generates, 32 = caller provides */ + __u64 nonce; /* user-space pointer to nonce (or 0) */ + __u64 public_key; /* user-space pointer to public key (64B) */ + __u64 ciphertext; /* [out] user-space pointer to C1 (64B) */ + __u64 enc_point; /* [out] user-space pointer to enc point (64B) */ + }; + +CMH_IOCTL_SM2_ENC_HASH +~~~~~~~~~~~~~~~~~~~~~~~ + +:Direction: ``_IOWR`` +:Number: 0x37 +:Argument: ``struct cmh_ioctl_sm2_enc_hash`` + +:: + + struct cmh_ioctl_sm2_enc_hash { + __u32 version; + __u32 message_len; /* message length (1..32) */ + __u64 message; /* user-space pointer to plaintext */ + __u64 enc_point; /* user-space pointer to enc point (64B) */ + __u64 ciphertext; /* [out] user-space pointer to ciphertext */ + }; + +CMH_IOCTL_SM2_DEC_POINT +~~~~~~~~~~~~~~~~~~~~~~~~ + +:Direction: ``_IOWR`` +:Number: 0x32 +:Argument: ``struct cmh_ioctl_sm2_dec_point`` + +:: + + struct cmh_ioctl_sm2_dec_point { + __u32 version; + __u32 ciphertext_len; /* total ciphertext length (97..128) */ + __u64 ciphertext; /* user-space pointer to ciphertext (64B: C1) */ + __u64 dec_point; /* [out] user-space pointer to dec point (64B) */ + __u64 key_ref; /* private key DS reference */ + }; + +CMH_IOCTL_SM2_DEC_HASH +~~~~~~~~~~~~~~~~~~~~~~~ + +:Direction: ``_IOWR`` +:Number: 0x36 +:Argument: ``struct cmh_ioctl_sm2_dec_hash`` + +:: + + struct cmh_ioctl_sm2_dec_hash { + __u32 version; + __u32 ciphertext_len; /* ciphertext length (97..128) */ + __u64 ciphertext; /* user-space pointer to full ciphertext */ + __u64 dec_point; /* user-space pointer to dec point (64B) */ + __u64 plaintext; /* [out] user-space pointer to plaintext */ + }; + +SM2 Key Exchange (GM/T 0003.3) +------------------------------ + +The key exchange protocol is a multi-step flow: + +1. ``EC_KEYGEN(CMH_CURVE_SM2)`` -- generate a long-lived private key. +2. ``EC_PUBGEN`` -- derive the public key. +3. ``SM2_ID_DIGEST`` -- compute the SM3 identity digest (ZA). +4. ``SM2_ECDH_KEYGEN`` -- generate an ephemeral session key. +5. Exchange session keys with the peer. +6. ``SM2_ECDH`` -- compute the shared point. +7. ``SM2_ECDH_HASH`` -- derive the shared key from the shared point + and both parties' ZA digests. + +CMH_IOCTL_SM2_ECDH_KEYGEN +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Direction: ``_IOWR`` +:Number: 0x30 +:Argument: ``struct cmh_ioctl_sm2_ecdh_keygen`` + +:: + + struct cmh_ioctl_sm2_ecdh_keygen { + __u32 version; + __u32 nonce_len; /* 0 = HW generates r (written back), 32 = caller */ + __u64 nonce; /* [in/out] user-space pointer to nonce buffer (32B) */ + __u64 session_key; /* [out] user-space pointer to R=r*G (64B) */ + }; + +``nonce_len`` must be 0 or 32. If ``nonce_len=0``, the hardware +generates the ephemeral scalar and writes it back to the ``nonce`` +buffer. + +CMH_IOCTL_SM2_ECDH +~~~~~~~~~~~~~~~~~~~ + +:Direction: ``_IOWR`` +:Number: 0x31 +:Argument: ``struct cmh_ioctl_sm2_ecdh`` + +:: + + struct cmh_ioctl_sm2_ecdh { + __u32 version; + __u32 nonce_len; /* 0 = HW generates, 32 = caller provides */ + __u64 nonce; /* [in/out] user-space pointer to nonce r (32B) */ + __u64 peer_public_key; /* user-space pointer to peer pub key (64B) */ + __u64 peer_session_key; /* user-space pointer to peer session key (64B) */ + __u64 key_ref; /* private key DS reference */ + __u64 shared_point; /* [out] user-space pointer to shared point (64B) */ + __u64 shared_point_ref; /* [in/out] 0 = read-back; &ref = keep DS */ + }; + +If ``shared_point_ref`` points to a non-zero value, the shared point +is kept in the datastore for use by ``SM2_ECDH_HASH``. + +CMH_IOCTL_SM2_ID_DIGEST +~~~~~~~~~~~~~~~~~~~~~~~~ + +Compute the SM3 identity digest (ZA) for a public key and identity +string. + +:Direction: ``_IOWR`` +:Number: 0x34 +:Argument: ``struct cmh_ioctl_sm2_id_digest`` + +:: + + struct cmh_ioctl_sm2_id_digest { + __u32 version; + __u32 id_len; /* identity length in bytes (<=32) */ + __u64 id; /* user-space pointer to identity string */ + __u64 public_key; /* user-space pointer to public key (64B) */ + __u64 digest; /* [out] user-space pointer to ZA digest (32B) */ + }; + +CMH_IOCTL_SM2_ECDH_HASH +~~~~~~~~~~~~~~~~~~~~~~~~ + +Derive the shared key from the shared point and ZA digests. + +:Direction: ``_IOWR`` +:Number: 0x35 +:Argument: ``struct cmh_ioctl_sm2_ecdh_hash`` + +:: + + struct cmh_ioctl_sm2_ecdh_hash { + __u32 version; + __u32 __reserved; + __u64 peer_id_digest; /* ptr to Z_A -- initiator's digest (32B) */ + __u64 id_digest; /* ptr to Z_B -- responder's digest (32B) */ + __u64 shared_point_ref; /* DS reference from SM2_ECDH */ + __u64 shared_key; /* [out] ptr to shared key (16B) */ + }; + +.. important:: + + The digest fields use **absolute** ordering per GM/T 0003.3, not + relative own/peer ordering. Both parties must pass: + + - ``peer_id_digest`` = Z_A (initiator's digest) -- hashed first + - ``id_digest`` = Z_B (responder's digest) -- hashed second + +Hardware Management ioctls +========================== + +CMH_IOCTL_EAC_READ +------------------- + +Read and clear the hardware Error and Alarm Controller registers. + +:Direction: ``_IOWR`` +:Number: 0x0F +:Argument: ``struct cmh_ioctl_eac_read`` + +:: + + struct cmh_ioctl_eac_read { + __u32 version; + __u32 __reserved; + __u64 mailbox_notification; + __u32 hw_error; + __u32 hw_nmi; + __u32 hw_panic; + __u32 safety_fatal; + __u32 safety_notification; + __u32 sw_info0; + __u32 sw_info1; + __u32 sram_bank_errors[4]; + __u32 __pad; + }; + +The eSW atomically reads and clears the registers on each call. +Successive reads show only new events since the last read. + +CMH_IOCTL_DRBG_CONFIG +---------------------- + +Configure the hardware DRBG before first use. + +:Direction: ``_IOW`` +:Number: 0x40 +:Argument: ``struct cmh_ioctl_drbg_config`` + +:: + + struct cmh_ioctl_drbg_config { + __u32 version; + __u32 entropy_ratio; /* CMH_DRBG_RATIO_* */ + __u32 security_strength; /* CMH_DRBG_STRENGTH_* */ + __u32 __reserved; + }; + +This is a management operation normally performed once at system +startup. Must be called before any ``hwrng`` reads or DRBG generate +operations. + +ioctl Number Summary +==================== + +====================================== ==== ==== ========================================= +ioctl Dir Seq Argument +====================================== ==== ==== ========================================= +``CMH_IOCTL_KEY_NEW`` IOWR 0x01 ``cmh_ioctl_key_new`` +``CMH_IOCTL_KEY_WRITE`` IOW 0x02 ``cmh_ioctl_key_write`` +``CMH_IOCTL_KEY_READ`` IOWR 0x03 ``cmh_ioctl_key_read`` +``CMH_IOCTL_KEY_FIND`` IOWR 0x04 ``cmh_ioctl_key_find`` +``CMH_IOCTL_KEY_GRANT`` IOW 0x05 ``cmh_ioctl_key_grant`` +``CMH_IOCTL_KEY_DELETE`` IOW 0x06 ``cmh_ioctl_key_grant`` +``CMH_IOCTL_DS_EXPORT`` IOWR 0x07 ``cmh_ioctl_ds_export`` +``CMH_IOCTL_DS_IMPORT`` IOW 0x08 ``cmh_ioctl_ds_import`` +``CMH_IOCTL_KIC_HKDF1`` IOWR 0x09 ``cmh_ioctl_kic_hkdf1`` +``CMH_IOCTL_KIC_HKDF2`` IOWR 0x0A ``cmh_ioctl_kic_hkdf2`` +``CMH_IOCTL_KEY_NEW_RANDOM`` IOWR 0x0B ``cmh_ioctl_key_new`` +``CMH_IOCTL_KIC_AES_CMAC_KDF`` IOWR 0x0C ``cmh_ioctl_kic_aes_cmac_kdf`` +``CMH_IOCTL_KIC_DKEK_DERIVE`` IOWR 0x0D ``cmh_ioctl_kic_dkek_derive`` +``CMH_IOCTL_KEY_LIST`` IOWR 0x0E ``cmh_ioctl_key_list`` +``CMH_IOCTL_EAC_READ`` IOWR 0x0F ``cmh_ioctl_eac_read`` +``CMH_IOCTL_PKE_RSA_ENC`` IOWR 0x10 ``cmh_ioctl_pke_rsa_enc`` +``CMH_IOCTL_PKE_RSA_DEC`` IOWR 0x11 ``cmh_ioctl_pke_rsa_dec`` +``CMH_IOCTL_PKE_RSA_CRT_DEC`` IOWR 0x12 ``cmh_ioctl_pke_rsa_crt_dec`` +``CMH_IOCTL_PKE_RSA_KEYGEN`` IOWR 0x13 ``cmh_ioctl_pke_rsa_keygen`` +``CMH_IOCTL_PKE_ECDSA_SIGN`` IOWR 0x14 ``cmh_ioctl_pke_ecdsa_sign`` +``CMH_IOCTL_PKE_ECDH`` IOWR 0x16 ``cmh_ioctl_pke_ecdh`` +``CMH_IOCTL_PKE_ECDH_KEYGEN`` IOWR 0x17 ``cmh_ioctl_pke_ecdh_keygen`` +``CMH_IOCTL_PKE_EDDSA_SIGN`` IOWR 0x18 ``cmh_ioctl_pke_eddsa_sign`` +``CMH_IOCTL_PKE_EDDSA_VERIFY`` IOW 0x19 ``cmh_ioctl_pke_eddsa_verify`` +``CMH_IOCTL_PKE_EC_KEYGEN`` IOWR 0x1A ``cmh_ioctl_pke_ec_keygen`` +``CMH_IOCTL_PKE_EC_PUBGEN`` IOWR 0x1B ``cmh_ioctl_pke_ec_pubgen`` +``CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA`` IOWR 0x1C ``cmh_ioctl_pke_eddsa_keygen_sca`` +``CMH_IOCTL_ML_KEM_KEYGEN`` IOWR 0x20 ``cmh_ioctl_ml_kem_keygen`` +``CMH_IOCTL_ML_KEM_ENC`` IOWR 0x21 ``cmh_ioctl_ml_kem_enc`` +``CMH_IOCTL_ML_KEM_DEC`` IOWR 0x22 ``cmh_ioctl_ml_kem_dec`` +``CMH_IOCTL_ML_DSA_KEYGEN`` IOWR 0x23 ``cmh_ioctl_ml_dsa_keygen`` +``CMH_IOCTL_ML_DSA_SIGN`` IOWR 0x24 ``cmh_ioctl_ml_dsa_sign`` +``CMH_IOCTL_SLHDSA_KEYGEN`` IOWR 0x28 ``cmh_ioctl_slhdsa_keygen`` +``CMH_IOCTL_SLHDSA_SIGN`` IOWR 0x29 ``cmh_ioctl_slhdsa_sign`` +``CMH_IOCTL_SLHDSA_SIGN_PREHASH`` IOWR 0x2D ``cmh_ioctl_slhdsa_sign_prehash`` +``CMH_IOCTL_SM2_ECDH_KEYGEN`` IOWR 0x30 ``cmh_ioctl_sm2_ecdh_keygen`` +``CMH_IOCTL_SM2_ECDH`` IOWR 0x31 ``cmh_ioctl_sm2_ecdh`` +``CMH_IOCTL_SM2_DEC_POINT`` IOWR 0x32 ``cmh_ioctl_sm2_dec_point`` +``CMH_IOCTL_SM2_ENC_POINT`` IOWR 0x33 ``cmh_ioctl_sm2_enc_point`` +``CMH_IOCTL_SM2_ID_DIGEST`` IOWR 0x34 ``cmh_ioctl_sm2_id_digest`` +``CMH_IOCTL_SM2_ECDH_HASH`` IOWR 0x35 ``cmh_ioctl_sm2_ecdh_hash`` +``CMH_IOCTL_SM2_DEC_HASH`` IOWR 0x36 ``cmh_ioctl_sm2_dec_hash`` +``CMH_IOCTL_SM2_ENC_HASH`` IOWR 0x37 ``cmh_ioctl_sm2_enc_hash`` +``CMH_IOCTL_DRBG_CONFIG`` IOW 0x40 ``cmh_ioctl_drbg_config`` +====================================== ==== ==== ========================================= + +Relationship to the in-kernel crypto API +========================================= + +The main reason these operations are exposed as ioctls, rather than +through the standard in-kernel crypto API, is the CMH datastore key +model: an ioctl can operate on a *datastore-referenced* (hardware-held) +key, identified only by a ``ref`` or CID, whose raw bytes the CPU never +sees. The standard crypto API cannot express this -- every +``.setkey()`` takes raw key material -- so hardware key lifecycle +(create, import, derive, grant, destroy) and compute-on-hardware-held-key +operations have no crypto API equivalent and are only reachable here. + +These ioctls remain supported. Where an operation can *also* be +expressed through a standard kernel abstraction, additional in-kernel +crypto API bindings may be added over time; when such a binding lands the +driver registers through it, and the ioctl continues to be maintained for +backward compatibility: + +- **EdDSA** (``CMH_IOCTL_PKE_EDDSA_*``): a kernel ``sig`` binding may be + added once ed25519/ed448 algorithm types are accepted upstream. + +- **ML-KEM** (``CMH_IOCTL_ML_KEM_*``): a kernel KEM binding may be added + once the in-flight KEM subsystem series lands. + +- **Key lifecycle** (``CMH_IOCTL_KEY_*``): integration with the kernel + KEYS subsystem (trusted-keys / encrypted-keys) may be evaluated as a + follow-up series. + +Operations that are inherently vendor-specific (EAC Chip Authentication, +KIC key derivation, SM2 key exchange, DRBG configuration, datastore +export/import) have no corresponding kernel abstraction and are expected +to remain ioctl-only. diff --git a/Documentation/userspace-api/ioctl/index.rst b/Documentation/userspace-api/ioctl/index.rst index 475675eae086..bf88bb6b9a6f 100644 --- a/Documentation/userspace-api/ioctl/index.rst +++ b/Documentation/userspace-api/ioctl/index.rst @@ -12,4 +12,5 @@ IOCTLs ioctl-decoding cdrom + cmh_mgmt hdio diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 3f0ef1e27eb0..83fd74b6f396 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -170,6 +170,7 @@ Code Seq# Include File Comments 'I' all linux/isdn.h conflict! 'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict! 'I' 40-4F linux/mISDNif.h conflict! +'J' 01-40 uapi/linux/cmh_mgmt_ioctl.h Rambus CryptoManager Hub (CMH) 'K' all linux/kd.h 'L' 00-1F linux/loop.h conflict! 'L' 10-1F drivers/scsi/mpt3sas/mpt3sas_ctl.h conflict! -- 2.43.7