From patchwork Thu Feb 27 03:09:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993638 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 C6F86156230; Thu, 27 Feb 2025 03:10:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625814; cv=none; b=UWCvDVv3HeRM8RfOFWQqh/IABudvTsIMCEa8qWwRgfHWbuDNdQitvjzxWNEbsjZoPuH2ssN4ZD77EddIBg0mCNkh3cvHFK8D/ITY03x/686RvmrD7RR2pgLGw0cxoeJGgkb4sY6bJPqN0rsBiRWGZPF3SuydDqC8OVoATBZZMGk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625814; c=relaxed/simple; bh=k43xiz5nPDEHKcKEhnYdVXPBz4oVjuFkpTQHDNJTzRI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=XAB5186fTsb/kLtuoYCMc37StkbOapjPxrt/nxH3xSAuKG4v34kXH9NHRx+3nPv0YAT4OnH8IK6nmOOGPDqsSMTZ+6te7swvnS60kUrcoYuHMuV1V8H8zPaQQq53HTjypM3TvmKR1S0XAAwpq0C6yYfbL/v589Suezmyqrvo1p0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=MzWTCVjW; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=BZcgZO1y; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="MzWTCVjW"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="BZcgZO1y" Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfhigh.stl.internal (Postfix) with ESMTP id 4536625401FB; Wed, 26 Feb 2025 22:10:10 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Wed, 26 Feb 2025 22:10:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1740625810; x=1740712210; bh=hQUTYfWHalwJSgp8IozZ6vtvcxBd5eNM NXlU+aNvLgQ=; b=MzWTCVjW8lNLUm3l4gcm89D4RuXx8d26DhzAPtZ5didTRDXd /h5/HZ2rD3bYyv82Z6yW0EgBzKcM6THSBtNL4iCPEJfzFE3zgug+7yBeCeu3Dfb3 29vQwY4deaEY9ktLdKSd2QM4/5M8ddBhk0KS5gkSaJIhU+qt+dqOXvfY+s+snCJy WUw9iuzdyrjniB0AfD3ug4HgA7cWCSSoKl/S9hzu4K3JnW7WLa1UFwSm6t8jj3Qj E63EuipL6opTvOq0FE5wvJSxO83y/YjYTADvcy1JlaEayW3kxF/aZhPyWejzdX1M ZlESip6gQ4TF9YFVsJilIDW370qgWBVBt6M6+A== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1740625810; x= 1740712210; bh=hQUTYfWHalwJSgp8IozZ6vtvcxBd5eNMNXlU+aNvLgQ=; b=B ZcgZO1yNcUf1UYM/CLMWtxof5+33l6GcYlhzP2cX12tn9N0imTqj0JbMfiqZ2AGD SZz/pysw3qUYCcvxTuMGICIcs98miYos3Pyu6JThCPwQO+22kbIhFKfm1lpKVgbH ncDiQSLAduWqsv8v3gy6YXj0omBSXkbG+J158aud/sDUDDkLnZTGo00rCPoIpcmN MnunK+c7vKKad4dfk8uqtGNWGdAUZVAcpuWuWU08kj6oHvaQRblGC1YB6x2ul9Pj eSDr1e10lyYP6w32+msB+dq0ROIVEzo4ft2pD9fMNJADKVKqr0NsCmkZJg1o/z5a bEDLyCYraM034nVspkUWA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivg hnthhsucdlqddutddtmdenogfuohhrthgvugftvggtihhpvdculdegtddmnecujfgurhep hffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeetlhhishhtrghirh cuhfhrrghntghishcuoegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgeqnecu ggftrfgrthhtvghrnhepudefveevheeuffdttdfftddtgfekjedvvdetgeehtdeugfehvd duudeiudeffeehnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhf rhhomheprghlihhsthgrihhrsegrlhhishhtrghirhdvfedrmhgvpdhnsggprhgtphhtth hopedvvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtoheplhhinhhugidqtgiglhes vhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehlihhnuhigqdhkvghrnhgvlh esvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehluhhkrghsseifuhhnnhgv rhdruggvpdhrtghpthhtoheplhhinhhugidqphgtihesvhhgvghrrdhkvghrnhgvlhdroh hrghdprhgtphhtthhopegshhgvlhhgrggrshesghhoohhglhgvrdgtohhmpdhrtghpthht ohepjhhonhgrthhhrghnrdgtrghmvghrohhnsehhuhgrfigvihdrtghomhdprhgtphhtth hopehruhhsthdqfhhorhdqlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgt phhtthhopegrkhhpmheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpth htohepsghoqhhunhdrfhgvnhhgsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:03 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Dan Williams , Alistair Francis , =?utf-8?q?Ilpo_J=C3=A4rvinen?= Subject: [RFC v2 01/20] X.509: Make certificate parser public Date: Thu, 27 Feb 2025 13:09:33 +1000 Message-ID: <20250227030952.2319050-2-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner The upcoming support for PCI device authentication with CMA-SPDM (PCIe r6.1 sec 6.31) requires validating the Subject Alternative Name in X.509 certificates. High-level functions for X.509 parsing such as key_create_or_update() throw away the internal, low-level struct x509_certificate after extracting the struct public_key and public_key_signature from it. The Subject Alternative Name is thus inaccessible when using those functions. Afford CMA-SPDM access to the Subject Alternative Name by making struct x509_certificate public, together with the functions for parsing an X.509 certificate into such a struct and freeing such a struct. The private header file x509_parser.h previously included for the definition of time64_t. That definition was since moved to by commit 361a3bf00582 ("time64: Add time64.h header and define struct timespec64"), so adjust the #include directive as part of the move to the new public header file . No functional change intended. Signed-off-by: Lukas Wunner Reviewed-by: Dan Williams Reviewed-by: Alistair Francis Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron --- crypto/asymmetric_keys/x509_parser.h | 40 +-------------------- include/keys/x509-parser.h | 53 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 39 deletions(-) create mode 100644 include/keys/x509-parser.h diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 0688c222806b..39f1521b773d 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h @@ -5,49 +5,11 @@ * Written by David Howells (dhowells@redhat.com) */ -#include -#include -#include -#include - -struct x509_certificate { - struct x509_certificate *next; - struct x509_certificate *signer; /* Certificate that signed this one */ - struct public_key *pub; /* Public key details */ - struct public_key_signature *sig; /* Signature parameters */ - char *issuer; /* Name of certificate issuer */ - char *subject; /* Name of certificate subject */ - struct asymmetric_key_id *id; /* Issuer + Serial number */ - struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ - time64_t valid_from; - time64_t valid_to; - const void *tbs; /* Signed data */ - unsigned tbs_size; /* Size of signed data */ - unsigned raw_sig_size; /* Size of signature */ - const void *raw_sig; /* Signature data */ - const void *raw_serial; /* Raw serial number in ASN.1 */ - unsigned raw_serial_size; - unsigned raw_issuer_size; - const void *raw_issuer; /* Raw issuer name in ASN.1 */ - const void *raw_subject; /* Raw subject name in ASN.1 */ - unsigned raw_subject_size; - unsigned raw_skid_size; - const void *raw_skid; /* Raw subjectKeyId in ASN.1 */ - unsigned index; - bool seen; /* Infinite recursion prevention */ - bool verified; - bool self_signed; /* T if self-signed (check unsupported_sig too) */ - bool unsupported_sig; /* T if signature uses unsupported crypto */ - bool blacklisted; -}; +#include /* * x509_cert_parser.c */ -extern void x509_free_certificate(struct x509_certificate *cert); -DEFINE_FREE(x509_free_certificate, struct x509_certificate *, - if (!IS_ERR(_T)) x509_free_certificate(_T)) -extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); extern int x509_decode_time(time64_t *_t, size_t hdrlen, unsigned char tag, const unsigned char *value, size_t vlen); diff --git a/include/keys/x509-parser.h b/include/keys/x509-parser.h new file mode 100644 index 000000000000..37436a5c7526 --- /dev/null +++ b/include/keys/x509-parser.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* X.509 certificate parser + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#ifndef _KEYS_X509_PARSER_H +#define _KEYS_X509_PARSER_H + +#include +#include +#include +#include + +struct x509_certificate { + struct x509_certificate *next; + struct x509_certificate *signer; /* Certificate that signed this one */ + struct public_key *pub; /* Public key details */ + struct public_key_signature *sig; /* Signature parameters */ + char *issuer; /* Name of certificate issuer */ + char *subject; /* Name of certificate subject */ + struct asymmetric_key_id *id; /* Issuer + Serial number */ + struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ + time64_t valid_from; + time64_t valid_to; + const void *tbs; /* Signed data */ + unsigned tbs_size; /* Size of signed data */ + unsigned raw_sig_size; /* Size of signature */ + const void *raw_sig; /* Signature data */ + const void *raw_serial; /* Raw serial number in ASN.1 */ + unsigned raw_serial_size; + unsigned raw_issuer_size; + const void *raw_issuer; /* Raw issuer name in ASN.1 */ + const void *raw_subject; /* Raw subject name in ASN.1 */ + unsigned raw_subject_size; + unsigned raw_skid_size; + const void *raw_skid; /* Raw subjectKeyId in ASN.1 */ + unsigned index; + bool seen; /* Infinite recursion prevention */ + bool verified; + bool self_signed; /* T if self-signed (check unsupported_sig too) */ + bool unsupported_sig; /* T if signature uses unsupported crypto */ + bool blacklisted; +}; + +struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); +void x509_free_certificate(struct x509_certificate *cert); + +DEFINE_FREE(x509_free_certificate, struct x509_certificate *, + if (!IS_ERR(_T)) x509_free_certificate(_T)) + +#endif /* _KEYS_X509_PARSER_H */ From patchwork Thu Feb 27 03:09:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993639 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 21DAA156230; Thu, 27 Feb 2025 03:10:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625821; cv=none; b=ufgVHqjunJLNJfxM5Vg6rYLyIUa/jW4tn93IxqiizhQR+odx2BAk5NnoEp6W1bCeldzCYT3H7+2E+pWDNCIxQr+8WmVKggi+rIFEoj90R7ButHhw2xNqGJdQDC00ES156+1MJESPcysWQnfM8f8fILVt568DSDFrHtKw36cu99Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625821; c=relaxed/simple; bh=lCDrlsJ7HhJkdPJG7tFm1qooclxiQmkLar4cMvx90CA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ho5iIbCVYC+d/aM5Ej4iGekFAcQQd5PX8J/Q5Vt63t3gpBVxeKcOzZbylRvqKEeU0rpVm5ToOmchtdhFoaV7Fn5QQKHD7ASX7mUt5MIqswBdbNg+y7MeA4ifDFEVXEnPEybSgMr2tkSQuzrwOsFYPGOpvswhTR7KNArR9EETOK8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=GpwEFAvv; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=MLSfK1rD; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="GpwEFAvv"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="MLSfK1rD" Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfhigh.stl.internal (Postfix) with ESMTP id B6CB825401FF; Wed, 26 Feb 2025 22:10:17 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Wed, 26 Feb 2025 22:10:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1740625817; x=1740712217; bh=sJo14WZuKtMDUmj/Mfxd6IPJsbS6o55X +TKFuJLW9eY=; b=GpwEFAvvoGDrIOYywA31mz4gIVq0vWfp479GBmoZF+ynk2WN tp5hlpjYjBk+Y4PwfxulstMxymyAnk7Wwd6rZ7qoSEhchQZPGXe5hwACbGq9sqXV duOnTi2zFn0V4MVV2Qu87IiAY6HMsmb3gGrHzKrz35w+UA4Yt4uxL/7yeFXtYEg9 Lx/1o+Jg+kOIZQ/pe8v1qd9z7kZcHpxKW6jD250BDVIcjk0QGFgmXVwdfZVbt/um PwHMDoEp0wO9G+DG547Lv6HHss9sgP0uyuisv95dpczVB6EztIxAIcTM2ALs1Vyb 8zMiYguM4GDwArHqFHFJMHqeZMKWE1JQLkXNNg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1740625817; x= 1740712217; bh=sJo14WZuKtMDUmj/Mfxd6IPJsbS6o55X+TKFuJLW9eY=; b=M LSfK1rDMWvCutLXgsu/lyShqQ/k7vhzuP4tA0c5j5yIvB8f+UlHEnPEW9j4vC0Nj uT6Zk2juPrSGvJPT2sDY58l4pJxzdIA2J+/fglzF/frqlHKJ5BZvLSOOQUmNftZE v8k7ZVPL6HZQO0Cm/yNIPeMfrj6h1vStPKq6OlB00IdQn2wXH1wIcHpt7OQGF1iK WSVQ+EKdJ2ZbdEGvXIVAnVExG0e/18LQfyMOaT/o4R8EJO0RYI44xOOGz+uetj6o bidJNM5hsT3+qVbIZSAt2V/umvFhco90K7bXWkqxk0FKIV7XJe/cGsybFs2iaquO DbzbM6hyjLqipsgLl+ZjA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivg hnthhsucdlqddutddtmdenogfuohhrthgvugftvggtihhpvdculdegtddmnecujfgurhep hffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeetlhhishhtrghirh cuhfhrrghntghishcuoegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgeqnecu ggftrfgrthhtvghrnhepudefveevheeuffdttdfftddtgfekjedvvdetgeehtdeugfehvd duudeiudeffeehnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhf rhhomheprghlihhsthgrihhrsegrlhhishhtrghirhdvfedrmhgvpdhnsggprhgtphhtth hopedvvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtoheplhhinhhugidqtgiglhes vhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehlihhnuhigqdhkvghrnhgvlh esvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehluhhkrghsseifuhhnnhgv rhdruggvpdhrtghpthhtoheplhhinhhugidqphgtihesvhhgvghrrdhkvghrnhgvlhdroh hrghdprhgtphhtthhopegshhgvlhhgrggrshesghhoohhglhgvrdgtohhmpdhrtghpthht ohepjhhonhgrthhhrghnrdgtrghmvghrohhnsehhuhgrfigvihdrtghomhdprhgtphhtth hopehruhhsthdqfhhorhdqlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgt phhtthhopegrkhhpmheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpth htohepsghoqhhunhdrfhgvnhhgsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:11 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis , =?utf-8?q?Ilpo_J=C3=A4rvinen?= , Dan Williams Subject: [RFC v2 02/20] X.509: Parse Subject Alternative Name in certificates Date: Thu, 27 Feb 2025 13:09:34 +1000 Message-ID: <20250227030952.2319050-3-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner The upcoming support for PCI device authentication with CMA-SPDM (PCIe r6.1 sec 6.31) requires validating the Subject Alternative Name in X.509 certificates. Store a pointer to the Subject Alternative Name upon parsing for consumption by CMA-SPDM. Signed-off-by: Lukas Wunner Reviewed-by: Wilfred Mallawa Reviewed-by: Alistair Francis Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Acked-by: Dan Williams --- crypto/asymmetric_keys/x509_cert_parser.c | 9 +++++++++ include/keys/x509-parser.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index ee2fdab42334..ff1db59d4037 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -572,6 +572,15 @@ int x509_process_extension(void *context, size_t hdrlen, return 0; } + if (ctx->last_oid == OID_subjectAltName) { + if (ctx->cert->raw_san) + return -EBADMSG; + + ctx->cert->raw_san = v; + ctx->cert->raw_san_size = vlen; + return 0; + } + if (ctx->last_oid == OID_keyUsage) { /* * Get hold of the keyUsage bit string diff --git a/include/keys/x509-parser.h b/include/keys/x509-parser.h index 37436a5c7526..8e450befe3b9 100644 --- a/include/keys/x509-parser.h +++ b/include/keys/x509-parser.h @@ -36,6 +36,8 @@ struct x509_certificate { unsigned raw_subject_size; unsigned raw_skid_size; const void *raw_skid; /* Raw subjectKeyId in ASN.1 */ + const void *raw_san; /* Raw subjectAltName in ASN.1 */ + unsigned raw_san_size; unsigned index; bool seen; /* Infinite recursion prevention */ bool verified; From patchwork Thu Feb 27 03:09:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993640 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 8A427182BD; Thu, 27 Feb 2025 03:10:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625828; cv=none; b=kyJXVtNiY6g7JBOM/86EoWyNWoR3pagNSQX12Ocgi0AMSAxdIR26W90V8JUAtpR5oqKpZVlYyw9VcrxuZe50y9m2xO0iaffcKcgn7cX7i2k2AN5o3HBvIhsGc2QiNcvGjeRHdW8fyBTBaPWI9YPoaVwY2/Tc6xwOBMwGoJnwGnc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625828; c=relaxed/simple; bh=J0tzL8AvUlaJe55f+04+0KFIyGOTUTniwM5YasfexrI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=G1vhKMU7CwKDZKzrWWx25mQuJV2NftLhIEnp03N18J75rwHj7szMcD5btu/TEk3pJrFYohZHUjneMYVmlCjxqSn86/zghdnMvHFBvjLJ2/3z/JGNR7AjsVn9UuAcBRdMv6SqkHKrL3DnZaGsoFRxpmHeCxD7lyk5UuPO9I7kS0Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=Bm65ZSrF; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Y9gm5yV0; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="Bm65ZSrF"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Y9gm5yV0" Received: from phl-compute-13.internal (phl-compute-13.phl.internal [10.202.2.53]) by mailfout.stl.internal (Postfix) with ESMTP id 13EA8114017B; Wed, 26 Feb 2025 22:10:25 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-13.internal (MEProxy); Wed, 26 Feb 2025 22:10:25 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625824; x= 1740712224; bh=OOIx/3ju4JUTdg4HPClHZfHz0j8GooiHo98R2k5DRgo=; b=B m65ZSrFc7m+xbba2gV7s/vZgMEkbR/OQ78IBWPzXXQwLbdhWyppfQUuKAezhQhyQ 6yPhtl0Pv//mmeIcTVgciOzVc9n38GvyvFTPk+Sl9sLT3cbop4wDgnAwmernALBo mJ0oHEXe1H8UsXBZ7RNApb4Lwskzclcc68mDLM2qdItA4bJIpSStJU4fN3stXQGI Z+KPKOFRyOrvNtDlp1ZciIwY+BXqIu1/UvcKF8fJ6LhPVN6BU28nVBZyZ7o/G6jU TbxqEoI0MP1lQJ0icR6NjzbB9bz5iMg+q5SsHekOH/gC+pnqSNLAM+q3wNPqkDsU PG5zqwq6VUCMpf/3qUjLA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625824; x=1740712224; bh=O OIx/3ju4JUTdg4HPClHZfHz0j8GooiHo98R2k5DRgo=; b=Y9gm5yV0YiQyv3wK4 X7nQ17Lg43y0lRNh7dqfx2K+2w8Ck68WV3NGGJETKchiBiDynYXwFEkhH9eUDWuF oVG2FNPK0EAfkmeHsR/OyHEc6ipJreuII3268rh8rV4EO3XTL/lirvfH2iI9qIyW PtChjHTo95TOruTYx6AtxowW/8t7XmtVA4dVqjVAbJfLfMAAs53BTtx8uwExq9Bb e59bdLqhahwBeAakvKm5lM33C5GeiP8zSLVwQfw3QxgglFevtQC1+u9l0wVt/LJ0 XKLoOHxT006bNSGwFGogSO6IQDq4Ftt3UTH68bh5UmOz8nl/Mjap5SX+l5DB+NkD Vf3vw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivg hnthhsucdlqddutddtmdenogfuohhrthgvugftvggtihhpvdculdegtddmnecujfgurhep hffvvefufffkofgjfhgggfestdekredtredttdenucfhrhhomheptehlihhsthgrihhruc fhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlhhishhtrghirhdvfedrmhgvqeenucgg tffrrghtthgvrhhnpedutddvffeklefhgfefueegiefhkedujedttddukeeiueduudfhtd dtfeefveeghfenucffohhmrghinhepughmthhfrdhorhhgnecuvehluhhsthgvrhfuihii vgeptdenucfrrghrrghmpehmrghilhhfrhhomheprghlihhsthgrihhrsegrlhhishhtrg hirhdvfedrmhgvpdhnsggprhgtphhtthhopedvuddpmhhouggvpehsmhhtphhouhhtpdhr tghpthhtoheplhhinhhugidqtgiglhesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtph htthhopehlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgt phhtthhopehluhhkrghsseifuhhnnhgvrhdruggvpdhrtghpthhtoheplhhinhhugidqph gtihesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopegshhgvlhhgrggrshes ghhoohhglhgvrdgtohhmpdhrtghpthhtohepjhhonhgrthhhrghnrdgtrghmvghrohhnse hhuhgrfigvihdrtghomhdprhgtphhtthhopehruhhsthdqfhhorhdqlhhinhhugiesvhhg vghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopegrkhhpmheslhhinhhugidqfhhouh hnuggrthhiohhnrdhorhhgpdhrtghpthhtohepsghoqhhunhdrfhgvnhhgsehgmhgrihhl rdgtohhm X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:18 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Dan Williams , Alistair Francis Subject: [RFC v2 03/20] X.509: Move certificate length retrieval into new helper Date: Thu, 27 Feb 2025 13:09:35 +1000 Message-ID: <20250227030952.2319050-4-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner The upcoming in-kernel SPDM library (Security Protocol and Data Model, https://www.dmtf.org/dsp/DSP0274) needs to retrieve the length from ASN.1 DER-encoded X.509 certificates. Such code already exists in x509_load_certificate_list(), so move it into a new helper for reuse by SPDM. Export the helper so that SPDM can be tristate. (Some upcoming users of the SPDM libray may be modular, such as SCSI and ATA.) No functional change intended. Signed-off-by: Lukas Wunner Reviewed-by: Dan Williams Reviewed-by: Alistair Francis Reviewed-by: Jonathan Cameron --- crypto/asymmetric_keys/x509_loader.c | 38 +++++++++++++++++++--------- include/keys/asymmetric-type.h | 2 ++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/crypto/asymmetric_keys/x509_loader.c b/crypto/asymmetric_keys/x509_loader.c index a41741326998..25ff027fad1d 100644 --- a/crypto/asymmetric_keys/x509_loader.c +++ b/crypto/asymmetric_keys/x509_loader.c @@ -4,28 +4,42 @@ #include #include +ssize_t x509_get_certificate_length(const u8 *p, unsigned long buflen) +{ + ssize_t plen; + + /* Each cert begins with an ASN.1 SEQUENCE tag and must be more + * than 256 bytes in size. + */ + if (buflen < 4) + return -EINVAL; + + if (p[0] != 0x30 && + p[1] != 0x82) + return -EINVAL; + + plen = (p[2] << 8) | p[3]; + plen += 4; + if (plen > buflen) + return -EINVAL; + + return plen; +} +EXPORT_SYMBOL_GPL(x509_get_certificate_length); + int x509_load_certificate_list(const u8 cert_list[], const unsigned long list_size, const struct key *keyring) { key_ref_t key; const u8 *p, *end; - size_t plen; + ssize_t plen; p = cert_list; end = p + list_size; while (p < end) { - /* Each cert begins with an ASN.1 SEQUENCE tag and must be more - * than 256 bytes in size. - */ - if (end - p < 4) - goto dodgy_cert; - if (p[0] != 0x30 && - p[1] != 0x82) - goto dodgy_cert; - plen = (p[2] << 8) | p[3]; - plen += 4; - if (plen > end - p) + plen = x509_get_certificate_length(p, end - p); + if (plen < 0) goto dodgy_cert; key = key_create_or_update(make_key_ref(keyring, 1), diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index 69a13e1e5b2e..e2af07fec3c6 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h @@ -84,6 +84,8 @@ extern struct key *find_asymmetric_key(struct key *keyring, const struct asymmetric_key_id *id_2, bool partial); +ssize_t x509_get_certificate_length(const u8 *p, unsigned long buflen); + int x509_load_certificate_list(const u8 cert_list[], const unsigned long list_size, const struct key *keyring); From patchwork Thu Feb 27 03:09:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993641 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 E01F1182BD; Thu, 27 Feb 2025 03:10:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625837; cv=none; b=Ey8kA7GU/ngjoFMJbJr38C6HTW6YAASxFo/hIje3km9SL07O/fTTOY/QyKc4aMQ4j+md/I2XJhbfhgSZl1r/heFbb5cGhekXgdehPU0DLOOCRsZMiecPaoJDTXL5NxOGQ9wl4+yoo3Q2QisBbucy69lnJloBvLzZ3BJVX5izh/k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625837; c=relaxed/simple; bh=fNsLaSxDRLFdd3ko7FdqXCu+VNEYbma2oV2sbAhJCSo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=C9+v0cI0yd9OWPrYfmmmysJCLHVy/xyLRErNUCgD0XfV5o0mGcMa6G0+DwsRew5Qdbt5ICSnrv7RNQBXJr0AFxF08ZrkjWFuZC4XR/hraHHWHpmglxBKKGymrt6BxS8wZXJtDWBWOlj8omZnn1GIDpEiVNgyRmm/b/zUWIV5u2w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=WtILr1YJ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=oNjAUHsA; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="WtILr1YJ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="oNjAUHsA" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfhigh.stl.internal (Postfix) with ESMTP id 827AC2540202; Wed, 26 Feb 2025 22:10:33 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:10:34 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:subject:subject:to:to; s=fm1; t=1740625833; x=1740712233; bh=yMsEzbS3O6lUSMvQC5PcLR6pxn0YYtsN YDDhxRiwg6o=; b=WtILr1YJd7SMRdEfow8V3FpBolBQYIRvJKr1pjt8EUCAIxJ7 Xb98Jr9p7XDIltjgB/2CUIiFSJXEseaVcP9xt5wnqCFyuRN/t0RbE70DGn9cqceK F8Wq78YcDooZfh3xS0+LV/3iumf4RjH+1GT5/fetLmF1Li+pc5tn/4t3PhtOQNF4 K5D+y7MULf3TmIrFvNqLDtNftPQRfSr8UwYekSZUHTE14LrHlkdrpyND5gybQvrT a4bHlu4t8cRwtXWlGEm23JhDoNXt5z/NY/7cuYFuMe/bw6oLYf/tAWRoFWlyHes/ JBMxdmeyZgpO5BvrEeuF6UjKnCierQOXXZxSyw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1740625833; x= 1740712233; bh=yMsEzbS3O6lUSMvQC5PcLR6pxn0YYtsNYDDhxRiwg6o=; b=o NjAUHsAE7i6No2qZP33a0Z74GX3ADD993Ewh/glZwqwj9ZG5sOR2yKqYu5xstNYg nTPrhl7L0VET0T/kVsyDC8IQgs2s11VJ5EMRsnV7ldwyjHCfEIgRXWfdVJn2eRPt WSSqCnDqMOET2WqoxDmO0PIElqloUcHpS75PE5p1tvq9i+6dURdQ4KPtIlF1FTaW I53kj6vY+F3/f0278jyVK32XOfJfCLbGHqyxoikPORawLOb76iAija0uRScwDWZc EvZCTntHLl/S2L0gqWDIjHS+Ecc6wYwaOrxs8zxG6iNp9nmV8HnimKumyw8YcrVO DG1rsSNu08yCp2Zrp9qkQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivg hnthhsucdlqddutddtmdenogfuohhrthgvugftvggtihhpvdculdegtddmnecujfgurhep hffvvefufffkofgjfhggtgfgsehtkeertdertdejnecuhfhrohhmpeetlhhishhtrghirh cuhfhrrghntghishcuoegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgeqnecu ggftrfgrthhtvghrnhepudefveevheeuffdttdfftddtgfekjedvvdetgeehtdeugfehvd duudeiudeffeehnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhf rhhomheprghlihhsthgrihhrsegrlhhishhtrghirhdvfedrmhgvpdhnsggprhgtphhtth hopedvvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtoheplhhinhhugidqtgiglhes vhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehlihhnuhigqdhkvghrnhgvlh esvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehluhhkrghsseifuhhnnhgv rhdruggvpdhrtghpthhtoheplhhinhhugidqphgtihesvhhgvghrrdhkvghrnhgvlhdroh hrghdprhgtphhtthhopegshhgvlhhgrggrshesghhoohhglhgvrdgtohhmpdhrtghpthht ohepjhhonhgrthhhrghnrdgtrghmvghrohhnsehhuhgrfigvihdrtghomhdprhgtphhtth hopehruhhsthdqfhhorhdqlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgt phhtthhopegrkhhpmheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpth htohepsghoqhhunhdrfhgvnhhgsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:25 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Dan Williams , Alistair Francis , =?utf-8?q?Ilpo_J=C3=A4rvinen?= Subject: [RFC v2 04/20] certs: Create blacklist keyring earlier Date: Thu, 27 Feb 2025 13:09:36 +1000 Message-ID: <20250227030952.2319050-5-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner The upcoming support for PCI device authentication with CMA-SPDM (PCIe r6.2 sec 6.31) requires parsing X.509 certificates upon device enumeration, which happens in a subsys_initcall(). Parsing X.509 certificates accesses the blacklist keyring: x509_cert_parse() x509_get_sig_params() is_hash_blacklisted() keyring_search() So far the keyring is created much later in a device_initcall(). Avoid a NULL pointer dereference on access to the keyring by creating it one initcall level earlier than PCI device enumeration, i.e. in an arch_initcall(). Signed-off-by: Lukas Wunner Reviewed-by: Dan Williams Reviewed-by: Wilfred Mallawa Reviewed-by: Alistair Francis Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron --- certs/blacklist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certs/blacklist.c b/certs/blacklist.c index 675dd7a8f07a..34185415d451 100644 --- a/certs/blacklist.c +++ b/certs/blacklist.c @@ -311,7 +311,7 @@ static int restrict_link_for_blacklist(struct key *dest_keyring, * Initialise the blacklist * * The blacklist_init() function is registered as an initcall via - * device_initcall(). As a result if the blacklist_init() function fails for + * arch_initcall(). As a result if the blacklist_init() function fails for * any reason the kernel continues to execute. While cleanly returning -ENODEV * could be acceptable for some non-critical kernel parts, if the blacklist * keyring fails to load it defeats the certificate/key based deny list for @@ -356,7 +356,7 @@ static int __init blacklist_init(void) /* * Must be initialised before we try and load the keys into the keyring. */ -device_initcall(blacklist_init); +arch_initcall(blacklist_init); #ifdef CONFIG_SYSTEM_REVOCATION_LIST /* From patchwork Thu Feb 27 03:09:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993642 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 3E59A1624C3; Thu, 27 Feb 2025 03:10:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625845; cv=none; b=YT2zh7S45bQKUA/qgeuVq985s3XftE6ztpl1aNB309dl9WdFRwFShT0ASU6l871gNmsyXFpj2WSP1zoyqt7vTrhD7pv2/Fr7XciE2szLAQIvkEGWrxHzR1+S+7Rw/7JdskWIvlRCHkEm6GHsmIq+2FkT12qjY8UB05Er1cg3dTQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625845; c=relaxed/simple; bh=Xb33wqwBjwnYEgWkSPmtSotdhdph4BsAyiHxX6eiz4w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XsVWjmGVYdXOVHIJSZmRe+jKjBoZQAeGqWjVoCW2c7OX8f61GmMiFhK4FINohSGLCwwz1HPRC2REywWIakGMUuHWAQYzEGwsLJOuaWd/EtS1wTGfEuzijIGUfuO20qILFIy45mxYR5kR+km7pvXs6t+7nVeJKsRpiQH7gYOCUs0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=A9YeWCPc; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=u7F88Yw6; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="A9YeWCPc"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="u7F88Yw6" Received: from phl-compute-03.internal (phl-compute-03.phl.internal [10.202.2.43]) by mailfout.stl.internal (Postfix) with ESMTP id C5AE51140197; Wed, 26 Feb 2025 22:10:41 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Wed, 26 Feb 2025 22:10:42 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625841; x= 1740712241; bh=QHYYanU9/fikbjXjGNrAJCVcxaYxU/vjJtAiwtzylc4=; b=A 9YeWCPcpCiauLDcDgRmoRyi+N9f2KQzAixF1P1DF6kUpwLRbOC/H7tG/YskoySCB fGmR6guMR+KamdGPWj7yw6+Pam9AMs6p+nCRdT+XfjiC0cYVdhFBXpVAZe/xX5s7 CpbJ4IYC8W/xhU2Mx+7XbQ4LucASMZWYhAZ+dQ8dGs95NvVUmAd2YaaFvpOhUwlO mMCExpoi/Op3mRbW4JaeHUwfuWmPn2OHoLmf+ErgBIFe6pRsJtsLUsFh9jUZ3voS D5+TGfFrMoZJKQxS3UJZWpieooGSHdbv54Hwrg3cg96740RIoio5O4ASYgMR5mBl KSvojL5zF6vnusJHbf2Mg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625841; x=1740712241; bh=Q HYYanU9/fikbjXjGNrAJCVcxaYxU/vjJtAiwtzylc4=; b=u7F88Yw63uZVFQWBz bPejD0zdEEvss3f1f+3Geo7rzO6xGRBu7TQ+FE6D6JJfM5Ng41ZQuEVXdc/6ejS0 ELJ7G1IRpNiypHoMgd/bY7HTSsJy3knkJXHHhjo+VAAVFm+ZvUAn4cILAZy0WlQf LJ6nSqoCUnFaNXjloYCGrlZCJILzE7AlKNbWQTJ1bKyKM1WG05+j2KT9qNopPbMg bzjUQak+a6g4orSzPMXGVLW1S5/oTlQtBxMO/s+q8wZGtYJqh4C9eXmDyWb7uf6Q TtipiSIPJkxHhghgJ301F6IA3AtRJQHyLmRl1Q6IiobUet2UiMidCyfa8efEoEOO msSXA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeevfefhudefheehgfetheeu feeuteefheejtdekvdeugfdvtdevieefjeeklefgveenucffohhmrghinhepkhgvrhhnvg hlrdhorhhgpdgumhhtfhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgdpnh gspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehlihhn uhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugi dqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhukhgr shesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghisehvghgvrhdrkh gvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgohhoghhlvgdrtgho mhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhurgifvghirdgtoh hmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrhdrkhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgurghtihhonhdroh hrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:34 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 05/20] lib: rspdm: Initial commit of Rust SPDM Date: Thu, 27 Feb 2025 13:09:37 +1000 Message-ID: <20250227030952.2319050-6-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This is the initial commit of the Rust SPDM library. It is based on and compatible with the C SPDM library in the kernel (lib/spdm). Signed-off-by: Alistair Francis --- MAINTAINERS | 12 ++ include/linux/spdm.h | 39 ++++++ lib/Kconfig | 16 +++ lib/Makefile | 2 + lib/rspdm/Makefile | 10 ++ lib/rspdm/consts.rs | 39 ++++++ lib/rspdm/lib.rs | 119 +++++++++++++++++ lib/rspdm/state.rs | 225 ++++++++++++++++++++++++++++++++ lib/rspdm/validator.rs | 66 ++++++++++ rust/bindings/bindings_helper.h | 2 + rust/kernel/error.rs | 3 + 11 files changed, 533 insertions(+) create mode 100644 include/linux/spdm.h create mode 100644 lib/rspdm/Makefile create mode 100644 lib/rspdm/consts.rs create mode 100644 lib/rspdm/lib.rs create mode 100644 lib/rspdm/state.rs create mode 100644 lib/rspdm/validator.rs diff --git a/MAINTAINERS b/MAINTAINERS index 1b0cc181db74..0f37dbdcfd77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21376,6 +21376,18 @@ M: Security Officers S: Supported F: Documentation/process/security-bugs.rst +SECURITY PROTOCOL AND DATA MODEL (SPDM) +M: Jonathan Cameron +M: Lukas Wunner +M: Alistair Francis +L: linux-coco@lists.linux.dev +L: linux-cxl@vger.kernel.org +L: linux-pci@vger.kernel.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/devsec/spdm.git +F: include/linux/spdm.h +F: lib/rspdm/ + SECURITY SUBSYSTEM M: Paul Moore M: James Morris diff --git a/include/linux/spdm.h b/include/linux/spdm.h new file mode 100644 index 000000000000..9835a3202a0e --- /dev/null +++ b/include/linux/spdm.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Copyright (C) 2021-22 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#ifndef _SPDM_H_ +#define _SPDM_H_ + +#include + +struct key; +struct device; +struct spdm_state; +struct x509_certificate; + +typedef ssize_t (spdm_transport)(void *priv, struct device *dev, + const void *request, size_t request_sz, + void *response, size_t response_sz); + +typedef int (spdm_validate)(struct device *dev, u8 slot, + struct x509_certificate *leaf_cert); + +struct spdm_state *spdm_create(struct device *dev, spdm_transport *transport, + void *transport_priv, u32 transport_sz, + struct key *keyring, spdm_validate *validate); + +int spdm_authenticate(struct spdm_state *spdm_state); + +void spdm_destroy(struct spdm_state *spdm_state); + +extern const struct attribute_group spdm_attr_group; + +#endif diff --git a/lib/Kconfig b/lib/Kconfig index dccb61b7d698..df9c96a440c5 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -714,6 +714,22 @@ config LWQ_TEST help Run boot-time test of light-weight queuing. +config RSPDM + bool "Rust SPDM" + select CRYPTO + select KEYS + select ASYMMETRIC_KEY_TYPE + select ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select X509_CERTIFICATE_PARSER + help + The Rust implementation of the Security Protocol and Data Model (SPDM) + allows for device authentication, measurement, key exchange and + encrypted sessions. + + Crypto algorithms negotiated with SPDM are limited to those enabled + in .config. Users of SPDM therefore need to also select + any algorithms they deem mandatory. + endmenu config GENERIC_IOREMAP diff --git a/lib/Makefile b/lib/Makefile index d5cfc7afbbb8..09e1cfe413ef 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -303,6 +303,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o obj-$(CONFIG_ASN1) += asn1_decoder.o obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o +obj-$(CONFIG_RSPDM) += rspdm/ + obj-$(CONFIG_FONT_SUPPORT) += fonts/ hostprogs := gen_crc32table diff --git a/lib/rspdm/Makefile b/lib/rspdm/Makefile new file mode 100644 index 000000000000..1f62ee2a882d --- /dev/null +++ b/lib/rspdm/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Rust implementation of the DMTF Security Protocol and Data Model (SPDM) +# https://www.dmtf.org/dsp/DSP0274 +# +# Copyright (C) 2024 Western Digital + +obj-$(CONFIG_RSPDM) += spdm.o + +spdm-y := lib.o diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs new file mode 100644 index 000000000000..311e34c7fae7 --- /dev/null +++ b/lib/rspdm/consts.rs @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Western Digital + +//! Constants used by the library +//! +//! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) +//! + +pub(crate) const SPDM_REQ: u8 = 0x80; +pub(crate) const SPDM_ERROR: u8 = 0x7f; + +#[expect(dead_code)] +#[derive(Clone, Copy)] +pub(crate) enum SpdmErrorCode { + InvalidRequest = 0x01, + InvalidSession = 0x02, + Busy = 0x03, + UnexpectedRequest = 0x04, + Unspecified = 0x05, + DecryptError = 0x06, + UnsupportedRequest = 0x07, + RequestInFlight = 0x08, + InvalidResponseCode = 0x09, + SessionLimitExceeded = 0x0a, + SessionRequired = 0x0b, + ResetRequired = 0x0c, + ResponseTooLarge = 0x0d, + RequestTooLarge = 0x0e, + LargeResponse = 0x0f, + MessageLost = 0x10, + InvalidPolicy = 0x11, + VersionMismatch = 0x41, + ResponseNotReady = 0x42, + RequestResynch = 0x43, + OperationFailed = 0x44, + NoPendingRequests = 0x45, + VendorDefinedError = 0xff, +} diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs new file mode 100644 index 000000000000..2bb716140e0a --- /dev/null +++ b/lib/rspdm/lib.rs @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Western Digital + +//! Top level library for SPDM +//! +//! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) +//! +//! +//! Top level library, including C compatible public functions to be called +//! from other subsytems. +//! +//! This mimics the C SPDM implementation in the kernel + +use core::ffi::{c_int, c_void}; +use core::ptr; +use core::slice::from_raw_parts_mut; +use kernel::prelude::*; +use kernel::{alloc::flags, bindings}; + +use crate::state::SpdmState; + +const __LOG_PREFIX: &[u8] = b"spdm\0"; + +mod consts; +mod state; +mod validator; + +/// spdm_create() - Allocate SPDM session +/// +/// `dev`: Responder device +/// `transport`: Transport function to perform one message exchange +/// `transport_priv`: Transport private data +/// `transport_sz`: Maximum message size the transport is capable of (in bytes) +/// `keyring`: Trusted root certificates +/// `validate`: Function to validate additional leaf certificate requirements +/// (optional, may be %NULL) +/// +/// Return a pointer to the allocated SPDM session state or NULL on error. +#[no_mangle] +pub unsafe extern "C" fn spdm_create( + dev: *mut bindings::device, + transport: bindings::spdm_transport, + transport_priv: *mut c_void, + transport_sz: u32, + keyring: *mut bindings::key, + validate: bindings::spdm_validate, +) -> *mut SpdmState { + match KBox::new( + SpdmState::new( + dev, + transport, + transport_priv, + transport_sz, + keyring, + validate, + ), + flags::GFP_KERNEL, + ) { + Ok(ret) => KBox::into_raw(ret) as *mut SpdmState, + Err(_) => ptr::null_mut(), + } +} + +/// spdm_exchange() - Perform SPDM message exchange with device +/// +/// @spdm_state: SPDM session state +/// @req: Request message +/// @req_sz: Size of @req +/// @rsp: Response message +/// @rsp_sz: Size of @rsp +/// +/// Send the request @req to the device via the @transport in @spdm_state and +/// receive the response into @rsp, respecting the maximum buffer size @rsp_sz. +/// The request version is automatically populated. +/// +/// Return response size on success or a negative errno. Response size may be +/// less than @rsp_sz and the caller is responsible for checking that. It may +/// also be more than expected (though never more than @rsp_sz), e.g. if the +/// transport receives only dword-sized chunks. +#[no_mangle] +pub unsafe extern "C" fn spdm_exchange( + state: &'static mut SpdmState, + req: *mut c_void, + req_sz: usize, + rsp: *mut c_void, + rsp_sz: usize, +) -> isize { + let request_buf: &mut [u8] = unsafe { from_raw_parts_mut(req as *mut u8, req_sz) }; + let response_buf: &mut [u8] = unsafe { from_raw_parts_mut(rsp as *mut u8, rsp_sz) }; + + match state.spdm_exchange(request_buf, response_buf) { + Ok(ret) => ret as isize, + Err(e) => e.to_errno() as isize, + } +} + +/// spdm_authenticate() - Authenticate device +/// +/// @spdm_state: SPDM session state +/// +/// Authenticate a device through a sequence of GET_VERSION, GET_CAPABILITIES, +/// NEGOTIATE_ALGORITHMS, GET_DIGESTS, GET_CERTIFICATE and CHALLENGE exchanges. +/// +/// Perform internal locking to serialize multiple concurrent invocations. +/// Can be called repeatedly for reauthentication. +/// +/// Return 0 on success or a negative errno. In particular, -EPROTONOSUPPORT +/// indicates authentication is not supported by the device. +#[no_mangle] +pub unsafe extern "C" fn spdm_authenticate(_state: &'static mut SpdmState) -> c_int { + 0 +} + +/// spdm_destroy() - Destroy SPDM session +/// +/// @spdm_state: SPDM session state +#[no_mangle] +pub unsafe extern "C" fn spdm_destroy(_state: &'static mut SpdmState) {} diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs new file mode 100644 index 000000000000..9ebd87603454 --- /dev/null +++ b/lib/rspdm/state.rs @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Western Digital + +//! The `SpdmState` struct and implementation. +//! +//! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) +//! + +use core::ffi::c_void; +use kernel::prelude::*; +use kernel::{ + bindings, + error::{code::EINVAL, to_result, Error}, + validate::Untrusted, +}; + +use crate::consts::{SpdmErrorCode, SPDM_ERROR, SPDM_REQ}; +use crate::validator::{SpdmErrorRsp, SpdmHeader}; + +/// The current SPDM session state for a device. Based on the +/// C `struct spdm_state`. +/// +/// `dev`: Responder device. Used for error reporting and passed to @transport. +/// `transport`: Transport function to perform one message exchange. +/// `transport_priv`: Transport private data. +/// `transport_sz`: Maximum message size the transport is capable of (in bytes). +/// Used as DataTransferSize in GET_CAPABILITIES exchange. +/// `keyring`: Keyring against which to check the first certificate in +/// responder's certificate chain. +/// `validate`: Function to validate additional leaf certificate requirements. +/// +/// `version`: Maximum common supported version of requester and responder. +/// Negotiated during GET_VERSION exchange. +/// +/// `authenticated`: Whether device was authenticated successfully. +#[expect(dead_code)] +pub struct SpdmState { + pub(crate) dev: *mut bindings::device, + pub(crate) transport: bindings::spdm_transport, + pub(crate) transport_priv: *mut c_void, + pub(crate) transport_sz: u32, + pub(crate) keyring: *mut bindings::key, + pub(crate) validate: bindings::spdm_validate, + + // Negotiated state + pub(crate) version: u8, + + pub(crate) authenticated: bool, +} + +impl SpdmState { + pub(crate) fn new( + dev: *mut bindings::device, + transport: bindings::spdm_transport, + transport_priv: *mut c_void, + transport_sz: u32, + keyring: *mut bindings::key, + validate: bindings::spdm_validate, + ) -> Self { + SpdmState { + dev, + transport, + transport_priv, + transport_sz, + keyring, + validate, + version: 0x10, + authenticated: false, + } + } + + fn spdm_err(&self, rsp: &SpdmErrorRsp) -> Result<(), Error> { + match rsp.error_code { + SpdmErrorCode::InvalidRequest => { + pr_err!("Invalid request\n"); + Err(EINVAL) + } + SpdmErrorCode::InvalidSession => { + if rsp.version == 0x11 { + pr_err!("Invalid session {:#x}\n", rsp.error_data); + Err(EINVAL) + } else { + pr_err!("Undefined error {:#x}\n", rsp.error_code as u8); + Err(EINVAL) + } + } + SpdmErrorCode::Busy => { + pr_err!("Busy\n"); + Err(EBUSY) + } + SpdmErrorCode::UnexpectedRequest => { + pr_err!("Unexpected request\n"); + Err(EINVAL) + } + SpdmErrorCode::Unspecified => { + pr_err!("Unspecified error\n"); + Err(EINVAL) + } + SpdmErrorCode::DecryptError => { + pr_err!("Decrypt error\n"); + Err(EIO) + } + SpdmErrorCode::UnsupportedRequest => { + pr_err!("Unsupported request {:#x}\n", rsp.error_data); + Err(EINVAL) + } + SpdmErrorCode::RequestInFlight => { + pr_err!("Request in flight\n"); + Err(EINVAL) + } + SpdmErrorCode::InvalidResponseCode => { + pr_err!("Invalid response code\n"); + Err(EINVAL) + } + SpdmErrorCode::SessionLimitExceeded => { + pr_err!("Session limit exceeded\n"); + Err(EBUSY) + } + SpdmErrorCode::SessionRequired => { + pr_err!("Session required\n"); + Err(EINVAL) + } + SpdmErrorCode::ResetRequired => { + pr_err!("Reset required\n"); + Err(ECONNRESET) + } + SpdmErrorCode::ResponseTooLarge => { + pr_err!("Response too large\n"); + Err(EINVAL) + } + SpdmErrorCode::RequestTooLarge => { + pr_err!("Request too large\n"); + Err(EINVAL) + } + SpdmErrorCode::LargeResponse => { + pr_err!("Large response\n"); + Err(EMSGSIZE) + } + SpdmErrorCode::MessageLost => { + pr_err!("Message lost\n"); + Err(EIO) + } + SpdmErrorCode::InvalidPolicy => { + pr_err!("Invalid policy\n"); + Err(EINVAL) + } + SpdmErrorCode::VersionMismatch => { + pr_err!("Version mismatch\n"); + Err(EINVAL) + } + SpdmErrorCode::ResponseNotReady => { + pr_err!("Response not ready\n"); + Err(EINPROGRESS) + } + SpdmErrorCode::RequestResynch => { + pr_err!("Request resynchronization\n"); + Err(ECONNRESET) + } + SpdmErrorCode::OperationFailed => { + pr_err!("Operation failed\n"); + Err(EINVAL) + } + SpdmErrorCode::NoPendingRequests => Err(ENOENT), + SpdmErrorCode::VendorDefinedError => { + pr_err!("Vendor defined error\n"); + Err(EINVAL) + } + } + } + + /// Start a SPDM exchange + /// + /// The data in `request_buf` is sent to the device and the response is + /// stored in `response_buf`. + pub(crate) fn spdm_exchange( + &self, + request_buf: &mut [u8], + response_buf: &mut [u8], + ) -> Result { + let header_size = core::mem::size_of::(); + let request: &mut SpdmHeader = Untrusted::new_mut(request_buf).validate_mut()?; + let response: &SpdmHeader = Untrusted::new_ref(response_buf).validate()?; + + let transport_function = self.transport.ok_or(EINVAL)?; + // SAFETY: `transport_function` is provided by the new(), we are + // calling the function. + let length = unsafe { + transport_function( + self.transport_priv, + self.dev, + request_buf.as_ptr() as *const c_void, + request_buf.len(), + response_buf.as_mut_ptr() as *mut c_void, + response_buf.len(), + ) as i32 + }; + to_result(length)?; + + if (length as usize) < header_size { + return Ok(length); // Truncated response is handled by callers + } + if response.code == SPDM_ERROR { + if length as usize >= core::mem::size_of::() { + // SAFETY: The response buffer will be at at least as large as + // `SpdmErrorRsp` so we can cast the buffer to `SpdmErrorRsp` which + // is a packed struct. + self.spdm_err(unsafe { &*(response_buf.as_ptr() as *const SpdmErrorRsp) })?; + } else { + return Err(EINVAL); + } + } + + if response.code != request.code & !SPDM_REQ { + pr_err!( + "Response code {:#x} does not match request code {:#x}\n", + response.code, + request.code + ); + to_result(-(bindings::EPROTO as i32))?; + } + + Ok(length) + } +} diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs new file mode 100644 index 000000000000..a0a3a2f46952 --- /dev/null +++ b/lib/rspdm/validator.rs @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Western Digital + +//! Related structs and their Validate implementations. +//! +//! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) +//! + +use crate::consts::SpdmErrorCode; +use core::mem; +use kernel::prelude::*; +use kernel::{ + error::{code::EINVAL, Error}, + validate::{Unvalidated, Validate}, +}; + +#[repr(C, packed)] +pub(crate) struct SpdmHeader { + pub(crate) version: u8, + pub(crate) code: u8, /* RequestResponseCode */ + pub(crate) param1: u8, + pub(crate) param2: u8, +} + +impl Validate<&Unvalidated<[u8]>> for &SpdmHeader { + type Err = Error; + + fn validate(unvalidated: &Unvalidated<[u8]>) -> Result { + let raw = unvalidated.raw(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_ptr(); + // CAST: `SpdmHeader` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + Ok(unsafe { &*ptr }) + } +} + +impl Validate<&mut Unvalidated<[u8]>> for &mut SpdmHeader { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated<[u8]>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `SpdmHeader` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + Ok(unsafe { &mut *ptr }) + } +} + +#[repr(C, packed)] +pub(crate) struct SpdmErrorRsp { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) error_code: SpdmErrorCode, + pub(crate) error_data: u8, +} diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index f46cf3bb7069..42aa62f0c8f5 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index f6ecf09cb65f..8ee8674ec485 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -83,6 +83,9 @@ macro_rules! declare_err { declare_err!(EIOCBQUEUED, "iocb queued, will get completion event."); declare_err!(ERECALLCONFLICT, "Conflict with recalled state."); declare_err!(ENOGRACE, "NFS file lock reclaim refused."); + declare_err!(ECONNRESET, "Connection reset by peer."); + declare_err!(EMSGSIZE, "Message too long."); + declare_err!(EINPROGRESS, "Operation now in progress."); } /// Generic integer kernel error. From patchwork Thu Feb 27 03:09:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993643 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 86FBB1A5B98; Thu, 27 Feb 2025 03:10:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625851; cv=none; b=nOF6AD7YMkj6pH2DueVEWf14BedKwlkc4tZrSiedXfFvVBn2OB8wQLEXUo5TjkaklT9vfqNKJwmkF7/jjcefLx/zB/F9vggzi2Fo+oNL5q13HvswfZMsVv2TmjjuRieJVS4HPNk4tjYp2JjyK2LHTdpK95cfFrSs6m/uPqdDYMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625851; c=relaxed/simple; bh=F+Lr1xfu683HdbPEJ94aSnfTkngI44RHtI/lbJR5LkA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=quTEx1c9F8wqN2tcvsOi13ROzQFjiVfvSCVKZdzKhctQsbwstTZsVkDP9+R5Dhex7vxScC4sGvxhGOPz+55EI0iQ3ix0fOHwEgGIxMHu+kr/Bv100wEbjQA/q4wqeKTpKFkE5YU312bxyj9srTYwJROJhBD7H37e7bG95kTTdq0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=bRCxjeo4; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=58SeoT9b; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="bRCxjeo4"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="58SeoT9b" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfhigh.stl.internal (Postfix) with ESMTP id 578E22540200; Wed, 26 Feb 2025 22:10:48 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:10:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625848; x= 1740712248; bh=f29hxzv4zGLQyokSaZ9Juyb4oTZBi+oHaB95+TG/kAk=; b=b RCxjeo4HUL5OwYaVc9mIsMd9glHe98GhRn8z9GFWdpJTIz32pEZbZfHobpPzJ6Fh ZBVrTtzaBfY+RWZ7LRXwkn7ZMQ+GLDstlpwTpIaBzlQlsClt6jDqCJdnuyipB09R z/HUS7wnnRuqamnHPw9hy1CFF6KDkdaMAF1Al2hZXrs8bZg6z/smojMDToOARl62 lX45TqZEkR0krUU/HH6cu6lfMIRn03HGteowLgY4ew+p7LuOm9h2CxN1xhvcC5Bj AtUNKYyX8G3cL/oYlfDkQiBpU9t25AycwNbNB9vNmmM/vXa4UBcWppthiUZ+pHOR QZnUv90cFhP7g5FlRGhgg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625848; x=1740712248; bh=f 29hxzv4zGLQyokSaZ9Juyb4oTZBi+oHaB95+TG/kAk=; b=58SeoT9bZYsSKv5YN MJhrqP+rcTJWVLFTmfcAug5PpsQ66f+HMlP18+QYOsBfltcotBEo/orvOJVXNra3 eyNIpNnQe+ilQiY4pq1/Fugt15Taai0sKx4HvXNYGQhn+U8wPXFqn1ql9SDCd5Z0 JRvTl0vZegXNb0gc2LLhF1uKaW69zHKhGgnObSZG72m78wuI9w8ubOZ4OqO3NBCI Q83RDHCyzbNkLjGYRliKW1YfbdSPdqRbKomuwZxZxDzgC4HxFuDrXQkLPGeN4/9z bnAyjkxfLcv+6iqEeT7wFHITIMJJGTwVt3RlYvyXaYzRP6f/xKfv4px/ZCrUXQky lElvw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeekhfetjeduudejudeljefg jedtgeeiudefhfeugeeiteehfefftedvfedvheevtdenucffohhmrghinhepughmthhfrd horhhgpdhkvghrnhgvlhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgdpnh gspghrtghpthhtohepudelpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehlihhn uhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugi dqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhukhgr shesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghisehvghgvrhdrkh gvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgohhoghhlvgdrtgho mhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhurgifvghirdgtoh hmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrhdrkhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgurghtihhonhdroh hrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:42 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me Subject: [RFC v2 06/20] PCI/CMA: Authenticate devices on enumeration Date: Thu, 27 Feb 2025 13:09:38 +1000 Message-ID: <20250227030952.2319050-7-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Jonathan Cameron Component Measurement and Authentication (CMA, PCIe r6.2 sec 6.31) allows for measurement and authentication of PCIe devices. It is based on the Security Protocol and Data Model specification (SPDM, https://www.dmtf.org/dsp/DSP0274). CMA-SPDM in turn forms the basis for Integrity and Data Encryption (IDE, PCIe r6.2 sec 6.33) because the key material used by IDE is transmitted over a CMA-SPDM session. As a first step, authenticate CMA-capable devices on enumeration. A subsequent commit will expose the result in sysfs. When allocating SPDM session state with spdm_create(), the maximum SPDM message length needs to be passed. Make the PCI_DOE_MAX_LENGTH macro public and calculate the maximum payload length from it. Credits: Jonathan wrote a proof-of-concept of this CMA implementation. Lukas reworked it for upstream. Wilfred contributed fixes for issues discovered during testing. Signed-off-by: Jonathan Cameron Co-developed-by: Wilfred Mallawa Signed-off-by: Wilfred Mallawa Co-developed-by: Lukas Wunner Signed-off-by: Lukas Wunner --- MAINTAINERS | 1 + drivers/pci/Kconfig | 13 ++++++ drivers/pci/Makefile | 2 + drivers/pci/cma.c | 101 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/doe.c | 3 -- drivers/pci/pci.h | 8 ++++ drivers/pci/probe.c | 1 + drivers/pci/remove.c | 1 + include/linux/pci-doe.h | 4 ++ include/linux/pci.h | 4 ++ 10 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 drivers/pci/cma.c diff --git a/MAINTAINERS b/MAINTAINERS index 0f37dbdcfd77..abb3b603299f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21385,6 +21385,7 @@ L: linux-cxl@vger.kernel.org L: linux-pci@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/devsec/spdm.git +F: drivers/pci/cma.c F: include/linux/spdm.h F: lib/rspdm/ diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 2fbd379923fd..80954adbff7d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -121,6 +121,19 @@ config XEN_PCIDEV_FRONTEND config PCI_ATS bool +config PCI_CMA + bool "Component Measurement and Authentication (CMA-SPDM)" + select CRYPTO_ECDSA + select CRYPTO_RSA + select CRYPTO_SHA256 + select CRYPTO_SHA512 + select PCI_DOE + select RSPDM + help + Authenticate devices on enumeration per PCIe r6.2 sec 6.31. + A PCI DOE mailbox is used as transport for DMTF SPDM based + authentication, measurement and secure channel establishment. + config PCI_DOE bool diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 67647f1880fb..3cbf2c226a2d 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,6 +38,8 @@ obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o obj-$(CONFIG_PCI_NPEM) += npem.o obj-$(CONFIG_PCIE_TPH) += tph.o +obj-$(CONFIG_PCI_CMA) += cma.o + # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c new file mode 100644 index 000000000000..7463cd1179f0 --- /dev/null +++ b/drivers/pci/cma.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Component Measurement and Authentication (CMA-SPDM, PCIe r6.2 sec 6.31) + * + * Copyright (C) 2021 Huawei + * Jonathan Cameron + * + * Copyright (C) 2022-24 Intel Corporation + */ + +#define dev_fmt(fmt) "CMA: " fmt + +#include +#include +#include +#include + +#include "pci.h" + +/* Keyring that userspace can poke certs into */ +static struct key *pci_cma_keyring; + +#define PCI_DOE_FEATURE_CMA 1 + +static ssize_t pci_doe_transport(void *priv, struct device *dev, + const void *request, size_t request_sz, + void *response, size_t response_sz) +{ + struct pci_doe_mb *doe = priv; + ssize_t rc; + + /* + * CMA-SPDM operation in non-D0 states is optional (PCIe r6.2 + * sec 6.31.3). The spec does not define a way to determine + * if it's supported, so resume to D0 unconditionally. + */ + rc = pm_runtime_resume_and_get(dev); + if (rc) + return rc; + + rc = pci_doe(doe, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_FEATURE_CMA, + request, request_sz, response, response_sz); + + pm_runtime_put(dev); + + return rc; +} + +void pci_cma_init(struct pci_dev *pdev) +{ + struct pci_doe_mb *doe; + + if (IS_ERR(pci_cma_keyring)) + return; + + if (!pci_is_pcie(pdev)) + return; + + doe = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG, + PCI_DOE_FEATURE_CMA); + if (!doe) + return; + + pdev->spdm_state = spdm_create(&pdev->dev, pci_doe_transport, doe, + PCI_DOE_MAX_PAYLOAD, pci_cma_keyring, + NULL); + if (!pdev->spdm_state) + return; + + /* + * Keep spdm_state allocated even if initial authentication fails + * to allow for provisioning of certificates and reauthentication. + */ + spdm_authenticate(pdev->spdm_state); +} + +void pci_cma_destroy(struct pci_dev *pdev) +{ + if (!pdev->spdm_state) + return; + + spdm_destroy(pdev->spdm_state); +} + +__init static int pci_cma_keyring_init(void) +{ + pci_cma_keyring = keyring_alloc(".cma", KUIDT_INIT(0), KGIDT_INIT(0), + current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | + KEY_USR_WRITE | KEY_USR_SEARCH, + KEY_ALLOC_NOT_IN_QUOTA | + KEY_ALLOC_SET_KEEP, NULL, NULL); + if (IS_ERR(pci_cma_keyring)) { + pr_err("PCI: Could not allocate .cma keyring\n"); + return PTR_ERR(pci_cma_keyring); + } + + return 0; +} +arch_initcall(pci_cma_keyring_init); diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index 7bd7892c5222..8ea37698082a 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -31,9 +31,6 @@ #define PCI_DOE_FLAG_CANCEL 0 #define PCI_DOE_FLAG_DEAD 1 -/* Max data object length is 2^18 dwords */ -#define PCI_DOE_MAX_LENGTH (1 << 18) - /** * struct pci_doe_mb - State for a single DOE mailbox * diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 01e51db8d285..69ba2ae9a0cd 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -448,6 +448,14 @@ static inline void pci_doe_destroy(struct pci_dev *pdev) { } static inline void pci_doe_disconnected(struct pci_dev *pdev) { } #endif +#ifdef CONFIG_PCI_CMA +void pci_cma_init(struct pci_dev *pdev); +void pci_cma_destroy(struct pci_dev *pdev); +#else +static inline void pci_cma_init(struct pci_dev *pdev) { } +static inline void pci_cma_destroy(struct pci_dev *pdev) { } +#endif + #ifdef CONFIG_PCI_NPEM void pci_npem_create(struct pci_dev *dev); void pci_npem_remove(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 246744d8d268..edf06055e805 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2565,6 +2565,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_rcec_init(dev); /* Root Complex Event Collector */ pci_doe_init(dev); /* Data Object Exchange */ pci_tph_init(dev); /* TLP Processing Hints */ + pci_cma_init(dev); /* Component Measurement & Auth */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index efc37fcb73e2..e6feab4e3c61 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -61,6 +61,7 @@ static void pci_destroy_dev(struct pci_dev *dev) list_del(&dev->bus_list); up_write(&pci_bus_sem); + pci_cma_destroy(dev); pci_doe_destroy(dev); pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h index 1f14aed4354b..0d3d7656c456 100644 --- a/include/linux/pci-doe.h +++ b/include/linux/pci-doe.h @@ -15,6 +15,10 @@ struct pci_doe_mb; +/* Max data object length is 2^18 dwords (including 2 dwords for header) */ +#define PCI_DOE_MAX_LENGTH (1 << 18) +#define PCI_DOE_MAX_PAYLOAD ((PCI_DOE_MAX_LENGTH - 2) * sizeof(u32)) + struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor, u8 type); diff --git a/include/linux/pci.h b/include/linux/pci.h index 47b31ad724fa..50c43546a32b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -528,6 +529,9 @@ struct pci_dev { #ifdef CONFIG_PCI_DOE struct xarray doe_mbs; /* Data Object Exchange mailboxes */ #endif +#ifdef CONFIG_PCI_CMA + struct spdm_state *spdm_state; /* Security Protocol and Data Model */ +#endif #ifdef CONFIG_PCI_NPEM struct npem *npem; /* Native PCIe Enclosure Management */ #endif From patchwork Thu Feb 27 03:09:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993660 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 3C9C81B0435; Thu, 27 Feb 2025 03:10:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625859; cv=none; b=tzuzl1aPxh55OQGkrf5Nkdq0hyntsThhYAcKCCvrVH83ORSKQMPafUnhfBxeQM4W+ibu4604NSekX+x6aQFJ7tGNSkK54FGDVDMo1gjSOFiUdmz4DBWjowtWxsrI/V37pgGekCb/vKA+EeyZfFcwUiM8YddW+6N4/NF+CsGgGGA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625859; c=relaxed/simple; bh=WXEQxyf95UzmiiByU+tddnaWbrRGZLStxcKQrkTjrBI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZVcnO1et8E24NK56A3vK/JMDXZ3BhUtlYtRoJQAQzQ5XfZPnS3Ch5FjCm8soObdnglEIt0QUHxVQ+jEiAC1n6iUh3n2gUykzOcrlWNNoDYaZIsIpymfsl+J7zIpiIpFWGHpwQRAEjUQdNMVOLaRT81oCqYBGwZjNqjK0AwxRe/M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=PlxDeLGZ; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=wsaQzy2t; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="PlxDeLGZ"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="wsaQzy2t" Received: from phl-compute-09.internal (phl-compute-09.phl.internal [10.202.2.49]) by mailfhigh.stl.internal (Postfix) with ESMTP id E3F2F2540204; Wed, 26 Feb 2025 22:10:55 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-09.internal (MEProxy); Wed, 26 Feb 2025 22:10:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625855; x= 1740712255; bh=iIlwbJ5ACCtkAmCpB7eY9vd5ptblS0MfSK2vl5shV+k=; b=P lxDeLGZI7WJnZThfQhcDtspqLNANvvUFufxpGJjHc5R+h4F8g/TGOtsubDX1sfFV 203dEdFLVqfCbEYX3CIX4cW1qI9vq4UUVIZmpuydGCxmMY7AYRVgVDRgfJ/Vupsz dxWat56ydg3a1M4w2Dzy+CmY29IDxuYk/XywJofh1FPhXfNdpExHMymUSzwBCOma T9p6dp4LwxixNawbnLrzxBUUGrj2dNR/A7e21rxSwvdpwnC2EgvfMzWs/hnDKd86 G/exTBkHAiSG52T8SsRA8E+pgawKECWoyaK1EFacRmuCCwKTIsGbDFXaN4VIe9Ik KdiE/mwOE8TIpxpwytujQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625855; x=1740712255; bh=i IlwbJ5ACCtkAmCpB7eY9vd5ptblS0MfSK2vl5shV+k=; b=wsaQzy2tcuquaaorB fVEduX8wgjaqSJLXrhCEABP057rO9CUZIa9RDbBNKO2UTgF/sBoQlqfW4UJtgBYX 2yhqTkze4UputG24q0S2C8Y44aPf2C1To/ZgyTshVD/CAMUGvyKRQfsbjOfdoBI2 ySc15kkUR5Vc+nJhRXDAU/J+23lrb5mZq5YLETbzm7ZrOyxzYCgdoOp4UcwGsPcV vw2JY/c5D6jY+MU+V++y/Zl79kgjL3Mgr5Q1LpH2TJAfqavzZYcOCAZix2ZTYOn5 RGdka8b3n29aZ76mfg3LqC+C37qzLGQDwkZJb+UXBR9jrbourezetY5yt93TzN/a WMC8Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeelheekteekfeeuvdfgkeev ueekhfegvdevudevhfeggfduheehudffgeevjeegueenucffohhmrghinhepohhrrghngh gvqdhlrggsshdrfhhrpdhrfhgtqdgvughithhorhdrohhrghenucevlhhushhtvghrufhi iigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsth grihhrvdefrdhmvgdpnhgspghrtghpthhtohepudelpdhmohguvgepshhmthhpohhuthdp rhgtphhtthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtg hpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhr tghpthhtoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqd hptghisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghs sehgohhoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonh eshhhurgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehv ghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfoh hunhgurghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghi lhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:49 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me Subject: [RFC v2 07/20] PCI/CMA: Validate Subject Alternative Name in certificates Date: Thu, 27 Feb 2025 13:09:39 +1000 Message-ID: <20250227030952.2319050-8-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner PCIe r6.1 sec 6.31.3 stipulates requirements for Leaf Certificates presented by devices, in particular the presence of a Subject Alternative Name which encodes the Vendor ID, Device ID, Device Serial Number, etc. This prevents a mismatch between the device identity in Config Space and the certificate. A device cannot misappropriate a certificate from a different device without also spoofing Config Space. As a corollary, it cannot dupe an arbitrary driver into binding to it. Only drivers which bind to the device identity in the Subject Alternative Name work (PCIe r6.1 sec 6.31 "Implementation Note: Overview of Threat Model"). The Subject Alternative Name is signed, hence constitutes a signed copy of a Config Space portion. It's the same concept as web certificates which contain a set of domain names in the Subject Alternative Name for identity verification. Parse the Subject Alternative Name using a small ASN.1 module and validate its contents. The theory of operation is explained in a comment at the top of the newly inserted code. This functionality is introduced in a separate commit on top of basic CMA-SPDM support to split the code into digestible, reviewable chunks. The CMA OID added here is taken from the official OID Repository (it's not documented in the PCIe Base Spec): https://oid-rep.orange-labs.fr/get/2.23.147 Side notes: * PCIe r6.2 removes the spec language on the Subject Alternative Name. It still "requires the leaf certificate to include the information typically used by system software for device driver binding", but no longer specifies how that information is encoded into the certificate. According to the editor of the PCIe Base Spec and the author of the CMA 1.1 ECN (which caused this change), FPGA cards which mutate their device identity at runtime (due to a firmware update) were thought as unable to satisfy the previous spec language. The Protocol Working Group could not agree on a better solution and therefore dropped the spec language entirely. They acknowledge that the requirement is now under-spec'd. Because products already exist which adhere to the Subject Alternative Name requirement per PCIe r6.1 sec 6.31.3, they recommended to "push through" and use it as the de facto standard. The FPGA concerns are easily overcome by reauthenticating the device after a firmware update, either via sysfs or pci_cma_reauthenticate() (added by a subsequent commit). * PCIe r6.1 sec 6.31.3 strongly recommends to verify that "the information provided in the Subject Alternative Name entry is signed by the vendor indicated by the Vendor ID." In other words, the root certificate on pci_cma_keyring which signs the device's certificate chain must have been created for a particular Vendor ID. Unfortunately the spec neglects to define how the Vendor ID shall be encoded into the root certificate. So the recommendation cannot be implemented at this point and it is thus possible that a vendor signs device certificates of a different vendor. * Instead of a Subject Alternative Name, Leaf Certificates may include "a Reference Integrity Manifest, e.g., see Trusted Computing Group" or "a pointer to a location where such a Reference Integrity Manifest can be obtained" (PCIe r6.1 sec 6.31.3). A Reference Integrity Manifest contains "golden" measurements which can be compared to actual measurements retrieved from a device. It serves a different purpose than the Subject Alternative Name, hence it is unclear why the spec says only either of them is necessary. It is also unclear how a Reference Integrity Manifest shall be encoded into a certificate. Hence ignore the Reference Integrity Manifest requirement. Signed-off-by: Lukas Wunner Reviewed-by: Jonathan Cameron # except ASN.1 --- drivers/pci/Makefile | 4 +- drivers/pci/cma.asn1 | 41 ++++++++++++ drivers/pci/cma.c | 123 ++++++++++++++++++++++++++++++++++- include/linux/oid_registry.h | 3 + 4 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 drivers/pci/cma.asn1 diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 3cbf2c226a2d..0b9c2f3ed84a 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -38,7 +38,9 @@ obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o obj-$(CONFIG_PCI_NPEM) += npem.o obj-$(CONFIG_PCIE_TPH) += tph.o -obj-$(CONFIG_PCI_CMA) += cma.o +obj-$(CONFIG_PCI_CMA) += cma.o cma.asn1.o +$(obj)/cma.o: $(obj)/cma.asn1.h +$(obj)/cma.asn1.o: $(obj)/cma.asn1.c $(obj)/cma.asn1.h # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ diff --git a/drivers/pci/cma.asn1 b/drivers/pci/cma.asn1 new file mode 100644 index 000000000000..da41421d4085 --- /dev/null +++ b/drivers/pci/cma.asn1 @@ -0,0 +1,41 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Component Measurement and Authentication (CMA-SPDM, PCIe r6.1 sec 6.31.3) +-- X.509 Subject Alternative Name (RFC 5280 sec 4.2.1.6) +-- +-- Copyright (C) 2008 IETF Trust and the persons identified as authors +-- of the code +-- +-- https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6 +-- +-- The ASN.1 module in RFC 5280 appendix A.1 uses EXPLICIT TAGS whereas the one +-- in appendix A.2 uses IMPLICIT TAGS. The kernel's simplified asn1_compiler.c +-- always uses EXPLICIT TAGS, hence this ASN.1 module differs from RFC 5280 in +-- that it adds IMPLICIT to definitions from appendix A.2 (such as GeneralName) +-- and omits EXPLICIT in those definitions. + +SubjectAltName ::= GeneralNames + +GeneralNames ::= SEQUENCE OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] IMPLICIT OtherName, + rfc822Name [1] IMPLICIT IA5String, + dNSName [2] IMPLICIT IA5String, + x400Address [3] ANY, + directoryName [4] ANY, + ediPartyName [5] IMPLICIT EDIPartyName, + uniformResourceIdentifier [6] IMPLICIT IA5String, + iPAddress [7] IMPLICIT OCTET STRING, + registeredID [8] IMPLICIT OBJECT IDENTIFIER + } + +OtherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER ({ pci_cma_note_oid }), + value [0] ANY ({ pci_cma_note_san }) + } + +EDIPartyName ::= SEQUENCE { + nameAssigner [0] ANY OPTIONAL, + partyName [1] ANY + } diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c index 7463cd1179f0..e974d489c7a2 100644 --- a/drivers/pci/cma.c +++ b/drivers/pci/cma.c @@ -10,16 +10,137 @@ #define dev_fmt(fmt) "CMA: " fmt +#include +#include +#include #include #include #include #include +#include "cma.asn1.h" #include "pci.h" /* Keyring that userspace can poke certs into */ static struct key *pci_cma_keyring; +/* + * The spdm_requester.c library calls pci_cma_validate() to check requirements + * for Leaf Certificates per PCIe r6.1 sec 6.31.3. + * + * pci_cma_validate() parses the Subject Alternative Name using the ASN.1 + * module cma.asn1, which calls pci_cma_note_oid() and pci_cma_note_san() + * to compare an OtherName against the expected name. + * + * The expected name is constructed beforehand by pci_cma_construct_san(). + * + * PCIe r6.2 drops the Subject Alternative Name spec language, even though + * it continues to require "the leaf certificate to include the information + * typically used by system software for device driver binding". Use the + * Subject Alternative Name per PCIe r6.1 for lack of a replacement and + * because it is the de facto standard among existing products. + */ +#define CMA_NAME_MAX sizeof("Vendor=1234:Device=1234:CC=123456:" \ + "REV=12:SSVID=1234:SSID=1234:1234567890123456") + +struct pci_cma_x509_context { + struct pci_dev *pdev; + u8 slot; + enum OID last_oid; + char expected_name[CMA_NAME_MAX]; + unsigned int expected_len; + unsigned int found:1; +}; + +int pci_cma_note_oid(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct pci_cma_x509_context *ctx = context; + + ctx->last_oid = look_up_OID(value, vlen); + + return 0; +} + +int pci_cma_note_san(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct pci_cma_x509_context *ctx = context; + + /* These aren't the drOIDs we're looking for. */ + if (ctx->last_oid != OID_CMA) + return 0; + + if (tag != ASN1_UTF8STR || + vlen != ctx->expected_len || + memcmp(value, ctx->expected_name, vlen) != 0) { + pci_err(ctx->pdev, "Leaf certificate of slot %u " + "has invalid Subject Alternative Name\n", ctx->slot); + return -EINVAL; + } + + ctx->found = true; + + return 0; +} + +static unsigned int pci_cma_construct_san(struct pci_dev *pdev, char *name) +{ + unsigned int len; + u64 serial; + + len = snprintf(name, CMA_NAME_MAX, + "Vendor=%04hx:Device=%04hx:CC=%06x:REV=%02hhx", + pdev->vendor, pdev->device, pdev->class, pdev->revision); + + if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) + len += snprintf(name + len, CMA_NAME_MAX - len, + ":SSVID=%04hx:SSID=%04hx", + pdev->subsystem_vendor, pdev->subsystem_device); + + serial = pci_get_dsn(pdev); + if (serial) + len += snprintf(name + len, CMA_NAME_MAX - len, + ":%016llx", serial); + + return len; +} + +static int pci_cma_validate(struct device *dev, u8 slot, + struct x509_certificate *leaf_cert) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_cma_x509_context ctx; + int ret; + + if (!leaf_cert->raw_san) { + pci_err(pdev, "Leaf certificate of slot %u " + "has no Subject Alternative Name\n", slot); + return -EINVAL; + } + + ctx.pdev = pdev; + ctx.slot = slot; + ctx.found = false; + ctx.expected_len = pci_cma_construct_san(pdev, ctx.expected_name); + + ret = asn1_ber_decoder(&cma_decoder, &ctx, leaf_cert->raw_san, + leaf_cert->raw_san_size); + if (ret == -EBADMSG || ret == -EMSGSIZE) + pci_err(pdev, "Leaf certificate of slot %u " + "has malformed Subject Alternative Name\n", slot); + if (ret < 0) + return ret; + + if (!ctx.found) { + pci_err(pdev, "Leaf certificate of slot %u " + "has no OtherName with CMA OID\n", slot); + return -EINVAL; + } + + return 0; +} + #define PCI_DOE_FEATURE_CMA 1 static ssize_t pci_doe_transport(void *priv, struct device *dev, @@ -63,7 +184,7 @@ void pci_cma_init(struct pci_dev *pdev) pdev->spdm_state = spdm_create(&pdev->dev, pci_doe_transport, doe, PCI_DOE_MAX_PAYLOAD, pci_cma_keyring, - NULL); + pci_cma_validate); if (!pdev->spdm_state) return; diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 6f9242259edc..44679f0a3fd6 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -145,6 +145,9 @@ enum OID { OID_id_rsassa_pkcs1_v1_5_with_sha3_384, /* 2.16.840.1.101.3.4.3.15 */ OID_id_rsassa_pkcs1_v1_5_with_sha3_512, /* 2.16.840.1.101.3.4.3.16 */ + /* PCI */ + OID_CMA, /* 2.23.147 */ + OID__NR }; From patchwork Thu Feb 27 03:09:40 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993661 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 14BCE1B21B5; Thu, 27 Feb 2025 03:11:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625865; cv=none; b=RGZkxcjTBotUjoLs9mBy2VddIoDT27EeRzhk7zAPKChzFJ2PreVvvfH8vFk313nYscQ8Vg7SgMh2kGGHF5X+6wjLkbojUs6IY/kJLFtsE/0u6KFUmtVES/h2Ipzb/d3s+6EkqT4WGQ281UWlm+DqruKlp7Bbjl3psmagqo5IfrQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625865; c=relaxed/simple; bh=lzr7fQoSOlz3qcUZVp7oldKdhrwHytiLUH5Z76q3iTY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tZgC6RFAVgbA1btWNM0qrtnKFZ5p7mKED8QQsyeNFWX9a0gnc3ImQx2UHQzJjCdCm8cEIlGiFdNtL8wr1KBH7h8AsZmHOXs3Ebcu+CkVKW/Z2wREkLR8fUh3ZugrTjt4vS+3meGYjW6xRo30IhoNzR+rcBtqORbjcHnsl4h2AZU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=fR6BDKqz; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=xqpnSk1l; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="fR6BDKqz"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="xqpnSk1l" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfout.stl.internal (Postfix) with ESMTP id A846B1140199; Wed, 26 Feb 2025 22:11:02 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:11:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625862; x= 1740712262; bh=7MZPNGyEHz7YQqqrumb3k4zZCVPZQwkJTHv4U15Cp0g=; b=f R6BDKqzdqwa1pniMWOOsqB2qHnpyQ2F55ZTabnUN9QcsM235BHhs7DZYc9S5HDqH mf4nPvrLFdOb2YwrRHz6kTpejpf3aLlTRBPwwj+N8obYRdciNzWq1EtMxg0oo7lm RqJ1ShvuchGmUzzWs0byDVcetixpzDVF/QnF6v5idBsrDj4H4QsFKMYAGGXUY+oH Q2KwilJrbO7TBbUDaBJfW/eZMq22R26WjfNO8o/FhgzJzrU0tH6f2dDmmRA6dIGP N1tTqjz1lKb9FdN6O6aKmGKy5s0M6fEjnIG0aYE0i1CUWPQXglyvrHXAySlA4QV0 AhyyMhfQgUAZiBJmLRFuA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625862; x=1740712262; bh=7 MZPNGyEHz7YQqqrumb3k4zZCVPZQwkJTHv4U15Cp0g=; b=xqpnSk1lg7ZvNsGf1 vQB3UWcdLA9VoKJ7R9GX8UU0p+K4nH5wO80fjp/wx3UabhyV8RT2qTkvV9yohI91 PkUW13McAsEsuQlv6f1UMN82eXgjTpHhSm9SxnBNdsrl4y4UER0sKxvz6q9zkasB S1yTsfY8Q7HLtbitg6FfC/PWabvj7JV51w8ZnfN0xrhW3EhO+JVmkKLVpyLoR1xY Oi3AOh/cvyKiVe3/CpgRQ0Sp3xAkfk2C7cGY0qKcgecU1TA8EvZMeb2Sw+OyOR2R fIflbk43/GX0kiyNV0/PPQiXiPDg9N4ch4/ugNv/fOwF40gGJb5ofsz57HVLKMJK CwJyA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:10:56 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 08/20] PCI/CMA: Reauthenticate devices on reset and resume Date: Thu, 27 Feb 2025 13:09:40 +1000 Message-ID: <20250227030952.2319050-9-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner CMA-SPDM state is lost when a device undergoes a Conventional Reset. (But not a Function Level Reset, PCIe r6.2 sec 6.6.2.) A D3cold to D0 transition implies a Conventional Reset (PCIe r6.2 sec 5.8). Thus, reauthenticate devices on resume from D3cold and on recovery from a Secondary Bus Reset or DPC-induced Hot Reset. The requirement to reauthenticate devices on resume from system sleep (and in the future reestablish IDE encryption) is the reason why SPDM needs to be in-kernel: During ->resume_noirq, which is the first phase after system sleep, the PCI core walks down the hierarchy, puts each device in D0, restores its config space and invokes the driver's ->resume_noirq callback. The driver is afforded the right to access the device already during this phase. To retain this usage model in the face of authentication and encryption, CMA-SPDM reauthentication and IDE reestablishment must happen during the ->resume_noirq phase, before the driver's first access to the device. The driver is thus afforded seamless authenticated and encrypted access until the last moment before suspend and from the first moment after resume. During the ->resume_noirq phase, device interrupts are not yet enabled. It is thus impossible to defer CMA-SPDM reauthentication to a user space component on an attached disk or on the network, making an in-kernel SPDM implementation mandatory. The same catch-22 exists on recovery from a Conventional Reset: A user space SPDM implementation might live on a device which underwent reset, rendering its execution impossible. Signed-off-by: Lukas Wunner Reviewed-by: Alistair Francis --- drivers/pci/cma.c | 15 +++++++++++++++ drivers/pci/pci-driver.c | 1 + drivers/pci/pci.c | 12 ++++++++++-- drivers/pci/pci.h | 2 ++ drivers/pci/pcie/err.c | 3 +++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c index e974d489c7a2..f2c435b04b92 100644 --- a/drivers/pci/cma.c +++ b/drivers/pci/cma.c @@ -195,6 +195,21 @@ void pci_cma_init(struct pci_dev *pdev) spdm_authenticate(pdev->spdm_state); } +/** + * pci_cma_reauthenticate() - Perform CMA-SPDM authentication again + * @pdev: Device to reauthenticate + * + * Can be called by drivers after device identity has mutated, + * e.g. after downloading firmware to an FPGA device. + */ +void pci_cma_reauthenticate(struct pci_dev *pdev) +{ + if (!pdev->spdm_state) + return; + + spdm_authenticate(pdev->spdm_state); +} + void pci_cma_destroy(struct pci_dev *pdev) { if (!pdev->spdm_state) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f57ea36d125d..6dd24ae2d1ee 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -566,6 +566,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev) pci_pm_power_up_and_verify_state(pci_dev); pci_restore_state(pci_dev); pci_pme_restore(pci_dev); + pci_cma_reauthenticate(pci_dev); } static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 869d204a70a3..b462bab597f7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5074,8 +5074,16 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe) rc = pci_dev_reset_slot_function(dev, probe); if (rc != -ENOTTY) - return rc; - return pci_parent_bus_reset(dev, probe); + goto done; + + rc = pci_parent_bus_reset(dev, probe); + +done: + /* CMA-SPDM state is lost upon a Conventional Reset */ + if (!probe) + pci_cma_reauthenticate(dev); + + return rc; } static int cxl_reset_bus_function(struct pci_dev *dev, bool probe) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 69ba2ae9a0cd..fa6e3ae10b67 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -451,9 +451,11 @@ static inline void pci_doe_disconnected(struct pci_dev *pdev) { } #ifdef CONFIG_PCI_CMA void pci_cma_init(struct pci_dev *pdev); void pci_cma_destroy(struct pci_dev *pdev); +void pci_cma_reauthenticate(struct pci_dev *pdev); #else static inline void pci_cma_init(struct pci_dev *pdev) { } static inline void pci_cma_destroy(struct pci_dev *pdev) { } +static inline void pci_cma_reauthenticate(struct pci_dev *pdev) { } #endif #ifdef CONFIG_PCI_NPEM diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 31090770fffc..0028582f0590 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -133,6 +133,9 @@ static int report_slot_reset(struct pci_dev *dev, void *data) pci_ers_result_t vote, *result = data; const struct pci_error_handlers *err_handler; + /* CMA-SPDM state is lost upon a Conventional Reset */ + pci_cma_reauthenticate(dev); + device_lock(&dev->dev); pdrv = dev->driver; if (!pdrv || !pdrv->err_handler || !pdrv->err_handler->slot_reset) From patchwork Thu Feb 27 03:09:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993662 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 9CC4E1991CA; Thu, 27 Feb 2025 03:11:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625873; cv=none; b=Fi8hziTMNn4j+zWdCfPihsrrsKji60hdrF3UmQgnIQIQlBwpMkVlD3XDrpzxWg7Cvj9x76cq0N337FHGx+tsB99ZXYY+O/YpMCdN5vLJLHUjz0/69a86e+e9YX1jAAshqgIxI7+kRUxDhWgBV4bRSHPsqThwu7eeoTbITFCQK5g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625873; c=relaxed/simple; bh=n+K3oafg8CG2dxmfeKMDA2RDUurNVL0dn+ZVYcpRiLU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Rk95C1lcFkAAemPN4kP/qfu24LBvZi3HFtS5ZBuu+EYhzC09a/HR7cpqdW6s6SSE+BzD0usdQQISEUXkEuzsqhwwFw84QsqoBkVZrukuv5qb8f7q/+iRdjFdwWJAka077pWGpFF4afpRz1aQ5J+nFxpHgAZQ8DNQc2nripNPwc4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=iz5sNTtl; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=ODYVQRb6; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="iz5sNTtl"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="ODYVQRb6" Received: from phl-compute-11.internal (phl-compute-11.phl.internal [10.202.2.51]) by mailfout.stl.internal (Postfix) with ESMTP id 788B111400A8; Wed, 26 Feb 2025 22:11:10 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-11.internal (MEProxy); Wed, 26 Feb 2025 22:11:11 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625870; x= 1740712270; bh=kEdrbCf5Rp7ZMtPW8kXeQ3LNTbh3Bi8xDHDXhTg3O/s=; b=i z5sNTtlaPQX9td1Ot30mYUQzq9NnPJQIXN7KQpWdmxAntP9rGHFO8hrJMO9VHk45 hKOPt1BUL7of8JlCpoaL147wy0lcTNchk8d9TjBCRgtiZxux9Gsiq/IfdF4oyUpH bcqM90rkXhO3Klcc99xJuPN5B4Wm7xZSPWk7BI6pL19cKm1iWfUW7as6SYubwmYl CpDNqJN1OPyKm4vlDalFHvNN2apjUHnPopCxoNrGFRoY+Qp2LzeyOn8DYQ5gLSHA B86zhlU4TXuycDSBzQu6oZ0tPoK5UF1CQrLRkIsLnO/7WuvD+uZzzZ+jEVoaPjq4 hOE+n7EcaRUvfikrBC5zA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625870; x=1740712270; bh=k EdrbCf5Rp7ZMtPW8kXeQ3LNTbh3Bi8xDHDXhTg3O/s=; b=ODYVQRb6NFNItMdGx y5fuwCgHEdOYs8TxCWtsPA4yOiD401kzL1ZMEIeK7J+rr8Gr/jdNeWvQuy/EVMa2 Knq70a2mnkcBs0G4Ikg6pCS7P+VOXiZyokMp8oISIISnXoiJACbC9t1ZJDTy4QzO yuuZjUKNlTchYIG/qXJxyYTG+FUfYRwM+V3BGRGOYrCSSaXw7qmoSouUsAx7Bkrz A7blRlcRS5En90Hs8Z09QVVxk5ABPuTRaIkFX/FOLaTIZxLqIrh6hlFkLonqFYpo gZKa4Xpf8RaPgrK1b2CcdrE79zzHZMTgVyQFy7B8rw4N7Wb3LCnj62Y8jK7xHHnl JLz8A== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeevfefhudefheehgfetheeu feeuteefheejtdekvdeugfdvtdevieefjeeklefgveenucffohhmrghinhepkhgvrhhnvg hlrdhorhhgpdgumhhtfhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr mhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgdpnh gspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehlihhn uhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugi dqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhukhgr shesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghisehvghgvrhdrkh gvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgohhoghhlvgdrtgho mhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhurgifvghirdgtoh hmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrhdrkhgvrhhnvghl rdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgurghtihhonhdroh hrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:03 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 09/20] PCI/CMA: Expose in sysfs whether devices are authenticated Date: Thu, 27 Feb 2025 13:09:41 +1000 Message-ID: <20250227030952.2319050-10-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Lukas Wunner The PCI core has just been amended to authenticate CMA-capable devices on enumeration and store the result in an "authenticated" bit in struct pci_dev->spdm_state. Expose the bit to user space through an eponymous sysfs attribute. Allow user space to trigger reauthentication (e.g. after it has updated the CMA keyring) by writing to the sysfs attribute. Implement the attribute in the SPDM library so that other bus types besides PCI may take advantage of it. They just need to add spdm_attr_group to the attribute groups of their devices and amend the dev_to_spdm_state() helper which retrieves the spdm_state for a given device. The helper may return an ERR_PTR if it couldn't be determined whether SPDM is supported by the device. The sysfs attribute is visible in that case but returns an error on access. This prevents downgrade attacks where an attacker disturbs memory allocation or DOE communication in order to create the appearance that SPDM is unsupported. Subject to further discussion, a future commit might add a user-defined policy to forbid driver binding to devices which failed authentication, similar to the "authorized" attribute for USB. Alternatively, authentication success might be signaled to user space through a uevent, whereupon it may bind a (blacklisted) driver. A uevent signaling authentication failure might similarly cause user space to unbind or outright remove the potentially malicious device. Traffic from devices which failed authentication could also be filtered through ACS I/O Request Blocking Enable (PCIe r6.2 sec 7.7.11.3) or through Link Disable (PCIe r6.2 sec 7.5.3.7). Unlike an IOMMU, that will not only protect the host, but also prevent malicious peer-to-peer traffic to other devices. Signed-off-by: Lukas Wunner [ Changes by AF: - Drop lib/spdm changes and replace with Rust implementation ] Signed-off-by: Alistair Francis --- Documentation/ABI/testing/sysfs-devices-spdm | 31 +++++++ MAINTAINERS | 3 +- drivers/pci/cma.c | 12 ++- drivers/pci/doe.c | 2 + drivers/pci/pci-sysfs.c | 3 + drivers/pci/pci.h | 5 + include/linux/pci.h | 12 +++ lib/rspdm/Makefile | 1 + lib/rspdm/lib.rs | 1 + lib/rspdm/req-sysfs.c | 97 ++++++++++++++++++++ lib/rspdm/sysfs.rs | 28 ++++++ 11 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-devices-spdm create mode 100644 lib/rspdm/req-sysfs.c create mode 100644 lib/rspdm/sysfs.rs diff --git a/Documentation/ABI/testing/sysfs-devices-spdm b/Documentation/ABI/testing/sysfs-devices-spdm new file mode 100644 index 000000000000..2d6e5d513231 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-spdm @@ -0,0 +1,31 @@ +What: /sys/devices/.../authenticated +Date: June 2024 +Contact: Lukas Wunner +Description: + This file contains 1 if the device authenticated successfully + with SPDM (Security Protocol and Data Model). It contains 0 if + the device failed authentication (and may thus be malicious). + + Writing "re" to this file causes reauthentication. + That may be opportune after updating the device keyring. + The device keyring of the PCI bus is named ".cma" + (Component Measurement and Authentication). + + Reauthentication may also be necessary after device identity + has mutated, e.g. after downloading firmware to an FPGA device. + + The file is not visible if authentication is unsupported + by the device. + + If the kernel could not determine whether authentication is + supported because memory was low or communication with the + device was not working, the file is visible but accessing it + fails with error code ENOTTY. + + This prevents downgrade attacks where an attacker consumes + memory or disturbs communication in order to create the + appearance that a device does not support authentication. + + The reason why authentication support could not be determined + is apparent from "dmesg". To re-probe authentication support + of PCI devices, exercise the "remove" and "rescan" attributes. diff --git a/MAINTAINERS b/MAINTAINERS index abb3b603299f..03e1076f915a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21385,7 +21385,8 @@ L: linux-cxl@vger.kernel.org L: linux-pci@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/devsec/spdm.git -F: drivers/pci/cma.c +F: Documentation/ABI/testing/sysfs-devices-spdm +F: drivers/pci/cma* F: include/linux/spdm.h F: lib/rspdm/ diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c index f2c435b04b92..59558714f143 100644 --- a/drivers/pci/cma.c +++ b/drivers/pci/cma.c @@ -171,8 +171,10 @@ void pci_cma_init(struct pci_dev *pdev) { struct pci_doe_mb *doe; - if (IS_ERR(pci_cma_keyring)) + if (IS_ERR(pci_cma_keyring)) { + pdev->spdm_state = ERR_PTR(-ENOTTY); return; + } if (!pci_is_pcie(pdev)) return; @@ -185,8 +187,10 @@ void pci_cma_init(struct pci_dev *pdev) pdev->spdm_state = spdm_create(&pdev->dev, pci_doe_transport, doe, PCI_DOE_MAX_PAYLOAD, pci_cma_keyring, pci_cma_validate); - if (!pdev->spdm_state) + if (!pdev->spdm_state) { + pdev->spdm_state = ERR_PTR(-ENOTTY); return; + } /* * Keep spdm_state allocated even if initial authentication fails @@ -204,7 +208,7 @@ void pci_cma_init(struct pci_dev *pdev) */ void pci_cma_reauthenticate(struct pci_dev *pdev) { - if (!pdev->spdm_state) + if (IS_ERR_OR_NULL(pdev->spdm_state)) return; spdm_authenticate(pdev->spdm_state); @@ -212,7 +216,7 @@ void pci_cma_reauthenticate(struct pci_dev *pdev) void pci_cma_destroy(struct pci_dev *pdev) { - if (!pdev->spdm_state) + if (IS_ERR_OR_NULL(pdev->spdm_state)) return; spdm_destroy(pdev->spdm_state); diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index 8ea37698082a..e4b609f613da 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -706,6 +706,7 @@ void pci_doe_init(struct pci_dev *pdev) if (IS_ERR(doe_mb)) { pci_err(pdev, "[%x] failed to create mailbox: %ld\n", offset, PTR_ERR(doe_mb)); + pci_cma_disable(pdev); continue; } @@ -714,6 +715,7 @@ void pci_doe_init(struct pci_dev *pdev) pci_err(pdev, "[%x] failed to insert mailbox: %d\n", offset, rc); pci_doe_destroy_mb(doe_mb); + pci_cma_disable(pdev); } } } diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index b46ce1a2c554..0645935fbcaf 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1804,6 +1804,9 @@ const struct attribute_group *pci_dev_attr_groups[] = { #endif #ifdef CONFIG_PCIEASPM &aspm_ctrl_attr_group, +#endif +#ifdef CONFIG_PCI_CMA + &spdm_attr_group, #endif NULL, }; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index fa6e3ae10b67..ad646b69a9c7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -452,10 +452,15 @@ static inline void pci_doe_disconnected(struct pci_dev *pdev) { } void pci_cma_init(struct pci_dev *pdev); void pci_cma_destroy(struct pci_dev *pdev); void pci_cma_reauthenticate(struct pci_dev *pdev); +static inline void pci_cma_disable(struct pci_dev *pdev) +{ + pdev->spdm_state = ERR_PTR(-ENOTTY); +} #else static inline void pci_cma_init(struct pci_dev *pdev) { } static inline void pci_cma_destroy(struct pci_dev *pdev) { } static inline void pci_cma_reauthenticate(struct pci_dev *pdev) { } +static inline void pci_cma_disable(struct pci_dev *pdev) { } #endif #ifdef CONFIG_PCI_NPEM diff --git a/include/linux/pci.h b/include/linux/pci.h index 50c43546a32b..696f5ce971f4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2704,6 +2704,18 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev) void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); #endif +#ifdef CONFIG_PCI_CMA +static inline struct spdm_state *pci_dev_to_spdm_state(struct pci_dev *pdev) +{ + return pdev->spdm_state; +} +#else +static inline struct spdm_state *pci_dev_to_spdm_state(struct pci_dev *pdev) +{ + return NULL; +} +#endif + #include #define pci_printk(level, pdev, fmt, arg...) \ diff --git a/lib/rspdm/Makefile b/lib/rspdm/Makefile index 1f62ee2a882d..f15b1437196b 100644 --- a/lib/rspdm/Makefile +++ b/lib/rspdm/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_RSPDM) += spdm.o spdm-y := lib.o +spdm-$(CONFIG_SYSFS) += req-sysfs.o diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index 2bb716140e0a..24064d3c4669 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -24,6 +24,7 @@ mod consts; mod state; +pub mod sysfs; mod validator; /// spdm_create() - Allocate SPDM session diff --git a/lib/rspdm/req-sysfs.c b/lib/rspdm/req-sysfs.c new file mode 100644 index 000000000000..11bacb04f08f --- /dev/null +++ b/lib/rspdm/req-sysfs.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Rust implementation of the DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Requester role: sysfs interface + * + * Copyright (C) 2023-24 Intel Corporation + * Copyright (C) 2024 Western Digital + */ + +#include + +int rust_authenticated_show(void *spdm_state, char *buf); + +/** + * dev_to_spdm_state() - Retrieve SPDM session state for given device + * + * @dev: Responder device + * + * Returns a pointer to the device's SPDM session state, + * %NULL if the device doesn't have one or + * %ERR_PTR if it couldn't be determined whether SPDM is supported. + * + * In the %ERR_PTR case, attributes are visible but return an error on access. + * This prevents downgrade attacks where an attacker disturbs memory allocation + * or communication with the device in order to create the appearance that SPDM + * is unsupported. E.g. with PCI devices, the attacker may foil CMA or DOE + * initialization by simply hogging memory. + */ +static void *dev_to_spdm_state(struct device *dev) +{ + if (dev_is_pci(dev)) + return pci_dev_to_spdm_state(to_pci_dev(dev)); + + /* Insert mappers for further bus types here. */ + + return NULL; +} + +/* authenticated attribute */ + +static umode_t spdm_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + void *spdm_state = dev_to_spdm_state(dev); + + if (IS_ERR_OR_NULL(spdm_state)) + return SYSFS_GROUP_INVISIBLE; + + return a->mode; +} + +static ssize_t authenticated_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + void *spdm_state = dev_to_spdm_state(dev); + int rc; + + if (IS_ERR_OR_NULL(spdm_state)) + return PTR_ERR(spdm_state); + + if (sysfs_streq(buf, "re")) { + rc = spdm_authenticate(spdm_state); + if (rc) + return rc; + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t authenticated_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void *spdm_state = dev_to_spdm_state(dev); + + if (IS_ERR_OR_NULL(spdm_state)) + return PTR_ERR(spdm_state); + + return rust_authenticated_show(spdm_state, buf); +} +static DEVICE_ATTR_RW(authenticated); + +static struct attribute *spdm_attrs[] = { + &dev_attr_authenticated.attr, + NULL +}; + +const struct attribute_group spdm_attr_group = { + .attrs = spdm_attrs, + .is_visible = spdm_attrs_are_visible, +}; diff --git a/lib/rspdm/sysfs.rs b/lib/rspdm/sysfs.rs new file mode 100644 index 000000000000..50901c55b8f7 --- /dev/null +++ b/lib/rspdm/sysfs.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Western Digital + +//! Rust sysfs helper functions +//! +//! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) +//! + +use crate::SpdmState; +use kernel::prelude::*; +use kernel::{bindings, fmt, str::CString}; + +/// Helper function for the sysfs `authenticated_show()`. +#[no_mangle] +pub extern "C" fn rust_authenticated_show(spdm_state: *mut SpdmState, buf: *mut u8) -> isize { + // SAFETY: The opaque pointer will be directly from the `spdm_create()` + // function, so we can safely reconstruct it. + let state = unsafe { KBox::from_raw(spdm_state) }; + + let fmt = match CString::try_from_fmt(fmt!("{}\n", state.authenticated)) { + Ok(f) => f, + Err(_e) => return 0, + }; + + // SAFETY: Calling a kernel C function with valid arguments + unsafe { bindings::sysfs_emit(buf, fmt.as_char_ptr()) as isize } +} From patchwork Thu Feb 27 03:09:42 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993663 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 927171B4F0A; Thu, 27 Feb 2025 03:11:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625881; cv=none; b=HlrHEKeMnFwQ5+QPpGTnSrzDkHqwIl23fFr+nuWBltA04YnKbeWKH44ZHfj9sFxNR0w09g65zcrlByceDd3LttAQuDER9H3DzaT6msEg1+HL7d7PIYF+ubjZmEVJAw1xQ4gP/0buiJX/0l/jlihv8WicLef/xGOPMKSDXLcNHPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625881; c=relaxed/simple; bh=wen8Kghp3uXHjcrYPZZjmR3nmFOOFu4DndvrMLZ4q/0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RdN0zXwuifmJ8afp0SRzWKYpmAwHcXlyTJwCMurbghKum+COefFTNJ22R6+Tw1iOpSGQjirzcuJbL2nET/JNLLukaQEeRBcVT0WiOiEBCoOBWwlKLNPEaavutjpnjlp5Od8ylXJYHd2mD17M7tCcHqMB+0hStR2z8gcllSjkXZE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=e1uWqyG6; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=b5G2910l; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="e1uWqyG6"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="b5G2910l" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfhigh.stl.internal (Postfix) with ESMTP id 3CE4525400E9; Wed, 26 Feb 2025 22:11:17 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:11:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625877; x= 1740712277; bh=5Zcn/zYRyQlZ/Snfqkm7jCZaa/+R7uulSjm9wgXjBKc=; b=e 1uWqyG69KondzMnqgro1EJW54I+9HjYVy0egNy8IrUEvtxo2X23KO4RN3mXyFrD6 pBE4/z7bnY7a8xrffWqmrou9iK0a7xiBC6CJtxnFL1nDuAWM4sAIzMv8110Yhx0s uHbQNm/G+b8DsNU6rk8LLynbXjb11MMtXAxamEgr5Z/YAbDlE9VmKxAWynM0TFUA A2jVYPq8Irt9mNxRYwqUNHL3enTpmLPSXxbPORUWV9xfkcH48wl4K1Mb3XBda88l blzA0q29f3bK5MZH77f0fF0zBEzhYRlr8qjNrNV9nvi2wJhuzT5xfeFA3k5cspiN secghk2+zgi4aZAeXbChg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625877; x=1740712277; bh=5 Zcn/zYRyQlZ/Snfqkm7jCZaa/+R7uulSjm9wgXjBKc=; b=b5G2910ldjBIc/K6K wk+IlqPFJKrZknu/S38LPZfLUXWMkWbImOwLwXDTr8noikXxalBdl8vu+G5knqEa amwbEmFkLQiI3slzMYLET9bPxvK5MS/HzCqS8517vA1cQa9RqNcg1VUNeGAjxPQT B03PEkWBqJW1XlIo9AZQFuaMPpK0AAUtipT32nU8LAKii9iHv0SpqiMZh216qH6b ptNzImVqsSPmWxpUbX+Cg3yh2TzQ6PsBgBERAydnoy7OCyb9pTCagoJ2fdfjOl6m bEtXOOw9MCCs5GhaBQjrlKCNHavGWd6jid1XE7DE6Nvhp0Ezava9vfVZfjSirjMa XGrRw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpedutddvffeklefhgfefueeg iefhkedujedttddukeeiueduudfhtddtfeefveeghfenucffohhmrghinhepughmthhfrd horhhgnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhep rghlihhsthgrihhrsegrlhhishhtrghirhdvfedrmhgvpdhnsggprhgtphhtthhopedvtd dpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtoheplhhinhhugidqtgiglhesvhhgvghr rdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehlihhnuhigqdhkvghrnhgvlhesvhhgvg hrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopehluhhkrghsseifuhhnnhgvrhdruggv pdhrtghpthhtoheplhhinhhugidqphgtihesvhhgvghrrdhkvghrnhgvlhdrohhrghdprh gtphhtthhopegshhgvlhhgrggrshesghhoohhglhgvrdgtohhmpdhrtghpthhtohepjhho nhgrthhhrghnrdgtrghmvghrohhnsehhuhgrfigvihdrtghomhdprhgtphhtthhopehruh hsthdqfhhorhdqlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthho pegrkhhpmheslhhinhhugidqfhhouhhnuggrthhiohhnrdhorhhgpdhrtghpthhtohepsg hoqhhunhdrfhgvnhhgsehgmhgrihhlrdgtohhm X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:11 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 10/20] lib: rspdm: Support SPDM get_version Date: Thu, 27 Feb 2025 13:09:42 +1000 Message-ID: <20250227030952.2319050-11-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Support the GET_VERSION SPDM command. Signed-off-by: Alistair Francis --- lib/rspdm/consts.rs | 17 +++++++++++ lib/rspdm/lib.rs | 6 +++- lib/rspdm/state.rs | 57 +++++++++++++++++++++++++++++++++-- lib/rspdm/validator.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 4 deletions(-) diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs index 311e34c7fae7..da7b0810f103 100644 --- a/lib/rspdm/consts.rs +++ b/lib/rspdm/consts.rs @@ -7,6 +7,20 @@ //! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) //! +use crate::validator::SpdmHeader; +use core::mem; + +/* SPDM versions supported by this implementation */ +pub(crate) const SPDM_VER_10: u8 = 0x10; +#[allow(dead_code)] +pub(crate) const SPDM_VER_11: u8 = 0x11; +#[allow(dead_code)] +pub(crate) const SPDM_VER_12: u8 = 0x12; +pub(crate) const SPDM_VER_13: u8 = 0x13; + +pub(crate) const SPDM_MIN_VER: u8 = SPDM_VER_10; +pub(crate) const SPDM_MAX_VER: u8 = SPDM_VER_13; + pub(crate) const SPDM_REQ: u8 = 0x80; pub(crate) const SPDM_ERROR: u8 = 0x7f; @@ -37,3 +51,6 @@ pub(crate) enum SpdmErrorCode { NoPendingRequests = 0x45, VendorDefinedError = 0xff, } + +pub(crate) const SPDM_GET_VERSION: u8 = 0x84; +pub(crate) const SPDM_GET_VERSION_LEN: usize = mem::size_of::() + 255; diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index 24064d3c4669..f8cb9766ed62 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -109,7 +109,11 @@ /// Return 0 on success or a negative errno. In particular, -EPROTONOSUPPORT /// indicates authentication is not supported by the device. #[no_mangle] -pub unsafe extern "C" fn spdm_authenticate(_state: &'static mut SpdmState) -> c_int { +pub unsafe extern "C" fn spdm_authenticate(state: &'static mut SpdmState) -> c_int { + if let Err(e) = state.get_version() { + return e.to_errno() as c_int; + } + 0 } diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index 9ebd87603454..dd1ccdfd166a 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -8,6 +8,7 @@ //! use core::ffi::c_void; +use core::slice::from_raw_parts_mut; use kernel::prelude::*; use kernel::{ bindings, @@ -15,8 +16,10 @@ validate::Untrusted, }; -use crate::consts::{SpdmErrorCode, SPDM_ERROR, SPDM_REQ}; -use crate::validator::{SpdmErrorRsp, SpdmHeader}; +use crate::consts::{ + SpdmErrorCode, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_MAX_VER, SPDM_MIN_VER, SPDM_REQ, +}; +use crate::validator::{GetVersionReq, GetVersionRsp, SpdmErrorRsp, SpdmHeader}; /// The current SPDM session state for a device. Based on the /// C `struct spdm_state`. @@ -65,7 +68,7 @@ pub(crate) fn new( transport_sz, keyring, validate, - version: 0x10, + version: SPDM_MIN_VER, authenticated: false, } } @@ -222,4 +225,52 @@ pub(crate) fn spdm_exchange( Ok(length) } + + /// Negoiate a supported SPDM version and store the information + /// in the `SpdmState`. + pub(crate) fn get_version(&mut self) -> Result<(), Error> { + let mut request = GetVersionReq::default(); + request.version = self.version; + + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let request_buf = unsafe { + from_raw_parts_mut( + &mut request as *mut _ as *mut u8, + core::mem::size_of::(), + ) + }; + + let mut response_vec: KVec = KVec::with_capacity(SPDM_GET_VERSION_LEN, GFP_KERNEL)?; + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let response_buf = + unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), SPDM_GET_VERSION_LEN) }; + + let rc = self.spdm_exchange(request_buf, response_buf)?; + + // SAFETY: `rc` bytes where inserted to the raw pointer by spdm_exchange + unsafe { response_vec.set_len(rc as usize) }; + + let response: &mut GetVersionRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + + let mut foundver = false; + for i in 0..response.version_number_entry_count { + // Creating a reference on a packed struct will result in + // undefined behaviour, so we operate on the raw data directly + let unaligned = core::ptr::addr_of_mut!(response.version_number_entries) as *mut u16; + let addr = unaligned.wrapping_add(i as usize); + let version = (unsafe { core::ptr::read_unaligned::(addr) } >> 8) as u8; + + if version >= self.version && version <= SPDM_MAX_VER { + self.version = version; + foundver = true; + } + } + + if !foundver { + pr_err!("No common supported version\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + Ok(()) + } } diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs index a0a3a2f46952..f69be6aa6280 100644 --- a/lib/rspdm/validator.rs +++ b/lib/rspdm/validator.rs @@ -7,6 +7,7 @@ //! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) //! +use crate::bindings::{__IncompleteArrayField, __le16}; use crate::consts::SpdmErrorCode; use core::mem; use kernel::prelude::*; @@ -15,6 +16,8 @@ validate::{Unvalidated, Validate}, }; +use crate::consts::SPDM_GET_VERSION; + #[repr(C, packed)] pub(crate) struct SpdmHeader { pub(crate) version: u8, @@ -64,3 +67,67 @@ pub(crate) struct SpdmErrorRsp { pub(crate) error_code: SpdmErrorCode, pub(crate) error_data: u8, } + +#[repr(C, packed)] +pub(crate) struct GetVersionReq { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, +} + +impl Default for GetVersionReq { + fn default() -> Self { + GetVersionReq { + version: 0, + code: SPDM_GET_VERSION, + param1: 0, + param2: 0, + } + } +} + +#[repr(C, packed)] +pub(crate) struct GetVersionRsp { + pub(crate) version: u8, + pub(crate) code: u8, + param1: u8, + param2: u8, + reserved: u8, + pub(crate) version_number_entry_count: u8, + pub(crate) version_number_entries: __IncompleteArrayField<__le16>, +} + +impl Validate<&mut Unvalidated>> for &mut GetVersionRsp { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let version_number_entries = *(raw.get(5).ok_or(ENOMEM))? as usize; + let total_expected_size = version_number_entries * 2 + 6; + if raw.len() < total_expected_size { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `GetVersionRsp` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let rsp: &mut GetVersionRsp = unsafe { &mut *ptr }; + + // Creating a reference on a packed struct will result in + // undefined behaviour, so we operate on the raw data directly + let unaligned = core::ptr::addr_of_mut!(rsp.version_number_entries) as *mut u16; + for version_offset in 0..version_number_entries { + let addr = unaligned.wrapping_add(version_offset); + let version = unsafe { core::ptr::read_unaligned::(addr) }; + unsafe { core::ptr::write_unaligned::(addr, version.to_le()) } + } + + Ok(rsp) + } +} From patchwork Thu Feb 27 03:09:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993664 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 24F3B1B6D1E; Thu, 27 Feb 2025 03:11:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625887; cv=none; b=G4+1pCdF9fhiurQcTkJqNc1ahWOPdqQuEyl7lesUF7DuOSkTTu645noX0W96tlPer6Emr+zZguu2MZcxaee8ywemXf5Wz6ba5GPlWLc7RWv0BLwYBzA9Twt/x+fipvhYpixYKzchvIHdyDEATt5aUektiKEVNk9czR8N1x6Ey7M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625887; c=relaxed/simple; bh=4dYavBGAZvR1zIBvbUyVRSek3sr6HHQGephV6qvbOGY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NIgiPaCGjtsrb+dkTps9CeN9bhHXR0AvyFfMcfAfS0OthXZ7KwT4AwuK64i4U/VqkI/YPUo9H8L4U6C1VaIqa5X4dbJR0qkHPSTMieuxxF3UDGH6TbFViSxJBKxIw+Mi+fd4RMD4OBCAp7OPgp4ge32jc4vuQ7v3Wolox+p9VEs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=iM/HMaKW; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=BaMgGavA; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="iM/HMaKW"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="BaMgGavA" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfhigh.stl.internal (Postfix) with ESMTP id 08EB82540115; Wed, 26 Feb 2025 22:11:24 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:11:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625883; x= 1740712283; bh=bEM8tVhnsdLYLYdndD+m0ib5kGm9xyvTcl4FxlXS7UM=; b=i M/HMaKWiU3tqekVehvNwJ4Biig09LStu5kmrNBgefHJQ8rPKG1f663+44WbbUWNi bPKUVlck56d+8+BrvTOlhi3tNVKukylxws2L3/PyoZKgaREApj5YHm8l+Q5YdLI9 kG71j135RkgRgci6LTqYIqv8pIx1YqeYLTwXCuRii+q4JuzA2hFMeV9qb+7nIiDu DPdYjnLj0rXOmEyH/Leov4Gm/j+xKZMjIM7Fc3AlvDbdPkASNz7fWuTWI1D4b2rp 74g7huVCy/unVTZmDIH5KSz0MXq6Wo5S0x+ibzvHCq8H/aOHqsvfYU1fQY9slvHn 6oUJqJc35PlT9gxdqlEgw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625883; x=1740712283; bh=b EM8tVhnsdLYLYdndD+m0ib5kGm9xyvTcl4FxlXS7UM=; b=BaMgGavAnQdOVfN3y I/Py8q1k6tRgVmj5OqFkfF5dgDWtby4noofuWySAK+5c1wpIaLOGqRASzeW/FcaJ hfGCQ8/2T5A47g4KTinUf2WpWdOlPWfK2I2FHjjemx3g+rMBnc2a6CjUuoCkT1ho gvyP+42455fRBh/gXLg5+17Gk2Gs+SM/9myo66r3PVRg4Y5/oA9J6xzKtTl4MHER Qm5WlMpxjCP3NzOOitmTTBPfbAE77NcZRj6zERGtfhd0Zll/0qaNjEillBPw6Jxj MG0e4cU2PhpotNm6RdG9ZJ0qaXs3GPP3qUJu3JVKv1x4QX1teh1LaedxYo8A/noe EVi4w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeekheduheejgfdtteefgeet geekieevveeuheegtdegffelhfeglefgvdffudetkeenucffohhmrghinhepthhrrghnsh hpohhrthgpshiirdhtohenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgr ihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhrvdefrdhmvgdpnhgspghrtg hpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehlihhnuhigqdgt gihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrh hnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheplhhukhgrshesfihu nhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghisehvghgvrhdrkhgvrhhnvg hlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgohhoghhlvgdrtghomhdprhgt phhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhurgifvghirdgtohhmpdhrtg hpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrhdrkhgvrhhnvghlrdhorhhg pdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgurghtihhonhdrohhrghdprh gtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:18 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 11/20] lib: rspdm: Support SPDM get_capabilities Date: Thu, 27 Feb 2025 13:09:43 +1000 Message-ID: <20250227030952.2319050-12-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Support the GET_CAPABILITIES SPDM command. Signed-off-by: Alistair Francis --- lib/rspdm/consts.rs | 18 ++++++++-- lib/rspdm/lib.rs | 4 +++ lib/rspdm/state.rs | 67 +++++++++++++++++++++++++++++++++++-- lib/rspdm/validator.rs | 76 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 160 insertions(+), 5 deletions(-) diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs index da7b0810f103..8a58351bf268 100644 --- a/lib/rspdm/consts.rs +++ b/lib/rspdm/consts.rs @@ -12,9 +12,7 @@ /* SPDM versions supported by this implementation */ pub(crate) const SPDM_VER_10: u8 = 0x10; -#[allow(dead_code)] pub(crate) const SPDM_VER_11: u8 = 0x11; -#[allow(dead_code)] pub(crate) const SPDM_VER_12: u8 = 0x12; pub(crate) const SPDM_VER_13: u8 = 0x13; @@ -54,3 +52,19 @@ pub(crate) enum SpdmErrorCode { pub(crate) const SPDM_GET_VERSION: u8 = 0x84; pub(crate) const SPDM_GET_VERSION_LEN: usize = mem::size_of::() + 255; + +pub(crate) const SPDM_GET_CAPABILITIES: u8 = 0xe1; +pub(crate) const SPDM_MIN_DATA_TRANSFER_SIZE: u32 = 42; + +// SPDM cryptographic timeout of this implementation: +// Assume calculations may take up to 1 sec on a busy machine, which equals +// roughly 1 << 20. That's within the limits mandated for responders by CMA +// (1 << 23 usec, PCIe r6.2 sec 6.31.3) and DOE (1 sec, PCIe r6.2 sec 6.30.2). +// Used in GET_CAPABILITIES exchange. +pub(crate) const SPDM_CTEXPONENT: u8 = 20; + +pub(crate) const SPDM_CERT_CAP: u32 = 1 << 1; +pub(crate) const SPDM_CHAL_CAP: u32 = 1 << 2; + +pub(crate) const SPDM_REQ_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP; +pub(crate) const SPDM_RSP_MIN_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP; diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index f8cb9766ed62..fe36333b2d24 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -114,6 +114,10 @@ return e.to_errno() as c_int; } + if let Err(e) = state.get_capabilities() { + return e.to_errno() as c_int; + } + 0 } diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index dd1ccdfd166a..288a77b3ab56 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -17,9 +17,12 @@ }; use crate::consts::{ - SpdmErrorCode, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_MAX_VER, SPDM_MIN_VER, SPDM_REQ, + SpdmErrorCode, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_MAX_VER, SPDM_MIN_DATA_TRANSFER_SIZE, + SPDM_MIN_VER, SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, +}; +use crate::validator::{ + GetCapabilitiesReq, GetCapabilitiesRsp, GetVersionReq, GetVersionRsp, SpdmErrorRsp, SpdmHeader, }; -use crate::validator::{GetVersionReq, GetVersionRsp, SpdmErrorRsp, SpdmHeader}; /// The current SPDM session state for a device. Based on the /// C `struct spdm_state`. @@ -35,6 +38,8 @@ /// /// `version`: Maximum common supported version of requester and responder. /// Negotiated during GET_VERSION exchange. +/// @rsp_caps: Cached capabilities of responder. +/// Received during GET_CAPABILITIES exchange. /// /// `authenticated`: Whether device was authenticated successfully. #[expect(dead_code)] @@ -48,6 +53,7 @@ pub struct SpdmState { // Negotiated state pub(crate) version: u8, + pub(crate) rsp_caps: u32, pub(crate) authenticated: bool, } @@ -69,6 +75,7 @@ pub(crate) fn new( keyring, validate, version: SPDM_MIN_VER, + rsp_caps: 0, authenticated: false, } } @@ -273,4 +280,60 @@ pub(crate) fn get_version(&mut self) -> Result<(), Error> { Ok(()) } + + /// Obtain the supported capabilities from an SPDM session and store the + /// information in the `SpdmState`. + pub(crate) fn get_capabilities(&mut self) -> Result<(), Error> { + let mut request = GetCapabilitiesReq::default(); + request.version = self.version; + + let (req_sz, rsp_sz) = match self.version { + SPDM_VER_10 => (4, 8), + SPDM_VER_11 => (8, 8), + _ => { + request.data_transfer_size = self.transport_sz.to_le(); + request.max_spdm_msg_size = request.data_transfer_size; + + ( + core::mem::size_of::(), + core::mem::size_of::(), + ) + } + }; + + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) }; + + let mut response_vec: KVec = KVec::with_capacity(rsp_sz, GFP_KERNEL)?; + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) }; + + let rc = self.spdm_exchange(request_buf, response_buf)?; + + if rc < (rsp_sz as i32) { + pr_err!("Truncated capabilities response\n"); + to_result(-(bindings::EIO as i32))?; + } + + // SAFETY: `rc` bytes where inserted to the raw pointer by spdm_exchange + unsafe { response_vec.set_len(rc as usize) }; + + let response: &mut GetCapabilitiesRsp = + Untrusted::new_mut(&mut response_vec).validate_mut()?; + + self.rsp_caps = u32::from_le(response.flags); + if (self.rsp_caps & SPDM_RSP_MIN_CAPS) != SPDM_RSP_MIN_CAPS { + to_result(-(bindings::EPROTONOSUPPORT as i32))?; + } + + if self.version >= SPDM_VER_12 { + if response.data_transfer_size < SPDM_MIN_DATA_TRANSFER_SIZE { + pr_err!("Malformed capabilities response\n"); + to_result(-(bindings::EPROTO as i32))?; + } + self.transport_sz = self.transport_sz.min(response.data_transfer_size); + } + + Ok(()) + } } diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs index f69be6aa6280..cd792c46767a 100644 --- a/lib/rspdm/validator.rs +++ b/lib/rspdm/validator.rs @@ -16,7 +16,7 @@ validate::{Unvalidated, Validate}, }; -use crate::consts::SPDM_GET_VERSION; +use crate::consts::{SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_VERSION, SPDM_REQ_CAPS}; #[repr(C, packed)] pub(crate) struct SpdmHeader { @@ -131,3 +131,77 @@ fn validate(unvalidated: &mut Unvalidated>) -> Result Ok(rsp) } } + +#[repr(C, packed)] +pub(crate) struct GetCapabilitiesReq { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + reserved1: u8, + pub(crate) ctexponent: u8, + reserved2: u16, + + pub(crate) flags: u32, + + /* End of SPDM 1.1 structure */ + pub(crate) data_transfer_size: u32, + pub(crate) max_spdm_msg_size: u32, +} + +impl Default for GetCapabilitiesReq { + fn default() -> Self { + GetCapabilitiesReq { + version: 0, + code: SPDM_GET_CAPABILITIES, + param1: 0, + param2: 0, + reserved1: 0, + ctexponent: SPDM_CTEXPONENT, + reserved2: 0, + flags: (SPDM_REQ_CAPS as u32).to_le(), + data_transfer_size: 0, + max_spdm_msg_size: 0, + } + } +} + +#[repr(C, packed)] +pub(crate) struct GetCapabilitiesRsp { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + reserved1: u8, + pub(crate) ctexponent: u8, + reserved2: u16, + + pub(crate) flags: u32, + + /* End of SPDM 1.1 structure */ + pub(crate) data_transfer_size: u32, + pub(crate) max_spdm_msg_size: u32, + + pub(crate) supported_algorithms: __IncompleteArrayField<__le16>, +} + +impl Validate<&mut Unvalidated>> for &mut GetCapabilitiesRsp { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `GetCapabilitiesRsp` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let rsp: &mut GetCapabilitiesRsp = unsafe { &mut *ptr }; + + Ok(rsp) + } +} From patchwork Thu Feb 27 03:09:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993665 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 4AE4C190692; Thu, 27 Feb 2025 03:11:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625895; cv=none; b=LBJu6LGvmSsmxjyQdbXt97AcJeWqHnVbGlCJ90myy3yX1UGXux3eH2zURU2asHBXsRqzEuBuZlktLS6OnoCXafncXzpXzLvMKJ9ewf1x3Bv9+fMZebFUTTmaIOO3FCRbOec6jps/n4tUUghxpypOlT9Tqf6U6ybBqxM5F1xSbyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625895; c=relaxed/simple; bh=rzYpgZLZuUYJzMu9QBpUD+XLWvftZuDiLoC9vJllpuE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K8XP3ikZlAUYgSjqh63ChyU7tHzSFLdj1R2lim44Ao0zyW0FL5LI98RhAmU/kiOalGkn9A2x0KlphV4kQfJ9IWr3zh12xaYzbjBP0GwdAC6HM36vqGzJhukOrafLrpGAk9yXjPUTwvcIcWxedb1ZjxBgiqDAq91/IiQpXUAR2LI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=SihsXEo1; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=CbAixCXE; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="SihsXEo1"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="CbAixCXE" Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfout.stl.internal (Postfix) with ESMTP id F178D11401A0; Wed, 26 Feb 2025 22:11:31 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Wed, 26 Feb 2025 22:11:32 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625891; x= 1740712291; bh=dUaNRxApP9skjepEsTYNSBikC/Rhnq3MSeo7e+Jsorc=; b=S ihsXEo1oIDmDIiWf0b/5taGD74A3VBVPWB2HO3sG0WmCqPXHajZj2KdpppJSOYmx iF/PaC4MFAp2Ln9maaDSp/DsR/51HpJ87OfWLWkskM7/4E/7g8ZWFDe9IRY9xZh9 scuzTQbwYZUjZJo0dqC66WhHpkSzqPARW4Skiwf2S0kpktVCdKHYdpDSo6AvFUd7 5GS2MkSk/lIxkjLlUgbC5O6Zlej7+FLWMP5K4YwqWyrq+6AWZkvxG8Za+4KCWp/s /Blwl7bPPu/lru5lbi+d/+x2fOAXNpPr4ZtQYCHWDjpC1MWa7/yoRm3aYsbuNzDk Xo06LdNdi9+d/mqYX/pWg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625891; x=1740712291; bh=d UaNRxApP9skjepEsTYNSBikC/Rhnq3MSeo7e+Jsorc=; b=CbAixCXERH3a1GeFo PQHa7f1l6zOIdyHRw0mlvRCnh5lLkmXdefk1scpV/6cxlH2/Z46VSmcpwLdDXJ3i ENCAnfusBbwulXsaQQ0IqAk4Q4cbmmFMDF5seBKpH3wQvIB0S36A9RXU7PbdgdAg MdLtJ0CVUdSD5n9TvDc2em93SCVVtIzNF6MInnGdjjU5RUH39RGo7UnxyfIevlix tHVcGb+RtCHP+1xI/9mTP3p+4vnSBKRNnbmRpquV9sMw4xzDFpQJ8L0fVp4KX9I/ KFFMXvsYjGxv7VU79dySsFT7wRHXMvblfTA0gkERbg5ECnW4tOmvYtTsjtgPQESP bXmxA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeevteeufeekheeiledtveeg heejffejheeugefhiefhhfehvdefteelgfeiieeuteenucffohhmrghinhepsggrshgvpg hhrghshhgprghlghgpnhgrmhgvrdgrshdpshhhrghshhdrihhspdgumhhtfhdrohhrghdp sggrshgvpggrshihmhgpshgvlhdrthhopdgsrghsvggphhgrshhhpghsvghlrdhtohdpmh gvrghsuhhrvghmvghnthgphhgrshhhpggrlhhgohdrthhonecuvehluhhsthgvrhfuihii vgeptdenucfrrghrrghmpehmrghilhhfrhhomheprghlihhsthgrihhrsegrlhhishhtrg hirhdvfedrmhgvpdhnsggprhgtphhtthhopedvtddpmhhouggvpehsmhhtphhouhhtpdhr tghpthhtoheplhhinhhugidqtgiglhesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtph htthhopehlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgt phhtthhopehluhhkrghsseifuhhnnhgvrhdruggvpdhrtghpthhtoheplhhinhhugidqph gtihesvhhgvghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopegshhgvlhhgrggrshes ghhoohhglhgvrdgtohhmpdhrtghpthhtohepjhhonhgrthhhrghnrdgtrghmvghrohhnse hhuhgrfigvihdrtghomhdprhgtphhtthhopehruhhsthdqfhhorhdqlhhinhhugiesvhhg vghrrdhkvghrnhgvlhdrohhrghdprhgtphhtthhopegrkhhpmheslhhinhhugidqfhhouh hnuggrthhiohhnrdhorhhgpdhrtghpthhtohepsghoqhhunhdrfhgvnhhgsehgmhgrihhl rdgtohhm X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:24 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 12/20] lib: rspdm: Support SPDM negotiate_algorithms Date: Thu, 27 Feb 2025 13:09:44 +1000 Message-ID: <20250227030952.2319050-13-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Support the NEGOTIATE_ALGORITHMS SPDM command. Signed-off-by: Alistair Francis --- lib/rspdm/consts.rs | 53 ++++++++ lib/rspdm/lib.rs | 16 ++- lib/rspdm/state.rs | 213 +++++++++++++++++++++++++++++++- lib/rspdm/validator.rs | 115 ++++++++++++++++- rust/bindgen_static_functions | 5 + rust/bindings/bindings_helper.h | 2 + 6 files changed, 398 insertions(+), 6 deletions(-) diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs index 8a58351bf268..d2f245c858cc 100644 --- a/lib/rspdm/consts.rs +++ b/lib/rspdm/consts.rs @@ -65,6 +65,59 @@ pub(crate) enum SpdmErrorCode { pub(crate) const SPDM_CERT_CAP: u32 = 1 << 1; pub(crate) const SPDM_CHAL_CAP: u32 = 1 << 2; +pub(crate) const SPDM_MEAS_CAP_MASK: u32 = 3 << 3; +pub(crate) const SPDM_KEY_EX_CAP: u32 = 1 << 9; pub(crate) const SPDM_REQ_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP; pub(crate) const SPDM_RSP_MIN_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP; + +pub(crate) const SPDM_NEGOTIATE_ALGS: u8 = 0xe3; + +pub(crate) const SPDM_MEAS_SPEC_DMTF: u8 = 1 << 0; + +pub(crate) const SPDM_ASYM_RSASSA_2048: u32 = 1 << 0; +pub(crate) const _SPDM_ASYM_RSAPSS_2048: u32 = 1 << 1; +pub(crate) const SPDM_ASYM_RSASSA_3072: u32 = 1 << 2; +pub(crate) const _SPDM_ASYM_RSAPSS_3072: u32 = 1 << 3; +pub(crate) const SPDM_ASYM_ECDSA_ECC_NIST_P256: u32 = 1 << 4; +pub(crate) const SPDM_ASYM_RSASSA_4096: u32 = 1 << 5; +pub(crate) const _SPDM_ASYM_RSAPSS_4096: u32 = 1 << 6; +pub(crate) const SPDM_ASYM_ECDSA_ECC_NIST_P384: u32 = 1 << 7; +pub(crate) const SPDM_ASYM_ECDSA_ECC_NIST_P521: u32 = 1 << 8; +pub(crate) const _SPDM_ASYM_SM2_ECC_SM2_P256: u32 = 1 << 9; +pub(crate) const _SPDM_ASYM_EDDSA_ED25519: u32 = 1 << 10; +pub(crate) const _SPDM_ASYM_EDDSA_ED448: u32 = 1 << 11; + +pub(crate) const SPDM_HASH_SHA_256: u32 = 1 << 0; +pub(crate) const SPDM_HASH_SHA_384: u32 = 1 << 1; +pub(crate) const SPDM_HASH_SHA_512: u32 = 1 << 2; + +#[cfg(CONFIG_CRYPTO_RSA)] +pub(crate) const SPDM_ASYM_RSA: u32 = + SPDM_ASYM_RSASSA_2048 | SPDM_ASYM_RSASSA_3072 | SPDM_ASYM_RSASSA_4096; +#[cfg(not(CONFIG_CRYPTO_RSA))] +pub(crate) const SPDM_ASYM_RSA: u32 = 0; + +#[cfg(CONFIG_CRYPTO_ECDSA)] +pub(crate) const SPDM_ASYM_ECDSA: u32 = + SPDM_ASYM_ECDSA_ECC_NIST_P256 | SPDM_ASYM_ECDSA_ECC_NIST_P384 | SPDM_ASYM_ECDSA_ECC_NIST_P521; +#[cfg(not(CONFIG_CRYPTO_ECDSA))] +pub(crate) const SPDM_ASYM_ECDSA: u32 = 0; + +#[cfg(CONFIG_CRYPTO_SHA256)] +pub(crate) const SPDM_HASH_SHA2_256: u32 = SPDM_HASH_SHA_256; +#[cfg(not(CONFIG_CRYPTO_SHA256))] +pub(crate) const SPDM_HASH_SHA2_256: u32 = 0; + +#[cfg(CONFIG_CRYPTO_SHA512)] +pub(crate) const SPDM_HASH_SHA2_384_512: u32 = SPDM_HASH_SHA_384 | SPDM_HASH_SHA_512; +#[cfg(not(CONFIG_CRYPTO_SHA512))] +pub(crate) const SPDM_HASH_SHA2_384_512: u32 = 0; + +pub(crate) const SPDM_ASYM_ALGOS: u32 = SPDM_ASYM_RSA | SPDM_ASYM_ECDSA; +pub(crate) const SPDM_HASH_ALGOS: u32 = SPDM_HASH_SHA2_256 | SPDM_HASH_SHA2_384_512; + +/* Maximum number of ReqAlgStructs sent by this implementation */ +// pub(crate) const SPDM_MAX_REQ_ALG_STRUCT: usize = 4; + +pub(crate) const SPDM_OPAQUE_DATA_FMT_GENERAL: u8 = 1 << 1; diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index fe36333b2d24..5eee5116d791 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -118,6 +118,10 @@ return e.to_errno() as c_int; } + if let Err(e) = state.negotiate_algs() { + return e.to_errno() as c_int; + } + 0 } @@ -125,4 +129,14 @@ /// /// @spdm_state: SPDM session state #[no_mangle] -pub unsafe extern "C" fn spdm_destroy(_state: &'static mut SpdmState) {} +pub unsafe extern "C" fn spdm_destroy(state: &'static mut SpdmState) { + if let Some(desc) = &mut state.desc { + unsafe { + bindings::kfree(*desc as *mut _ as *mut c_void); + } + } + + unsafe { + bindings::crypto_free_shash(state.shash); + } +} diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index 288a77b3ab56..0aff45339e0b 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -13,15 +13,21 @@ use kernel::{ bindings, error::{code::EINVAL, to_result, Error}, + str::CStr, validate::Untrusted, }; use crate::consts::{ - SpdmErrorCode, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_MAX_VER, SPDM_MIN_DATA_TRANSFER_SIZE, - SPDM_MIN_VER, SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, + SpdmErrorCode, SPDM_ASYM_ALGOS, SPDM_ASYM_ECDSA_ECC_NIST_P256, SPDM_ASYM_ECDSA_ECC_NIST_P384, + SPDM_ASYM_ECDSA_ECC_NIST_P521, SPDM_ASYM_RSASSA_2048, SPDM_ASYM_RSASSA_3072, + SPDM_ASYM_RSASSA_4096, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_HASH_ALGOS, SPDM_HASH_SHA_256, + SPDM_HASH_SHA_384, SPDM_HASH_SHA_512, SPDM_KEY_EX_CAP, SPDM_MAX_VER, SPDM_MEAS_CAP_MASK, + SPDM_MEAS_SPEC_DMTF, SPDM_MIN_DATA_TRANSFER_SIZE, SPDM_MIN_VER, SPDM_OPAQUE_DATA_FMT_GENERAL, + SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, }; use crate::validator::{ - GetCapabilitiesReq, GetCapabilitiesRsp, GetVersionReq, GetVersionRsp, SpdmErrorRsp, SpdmHeader, + GetCapabilitiesReq, GetCapabilitiesRsp, GetVersionReq, GetVersionRsp, NegotiateAlgsReq, + NegotiateAlgsRsp, RegAlg, SpdmErrorRsp, SpdmHeader, }; /// The current SPDM session state for a device. Based on the @@ -40,6 +46,28 @@ /// Negotiated during GET_VERSION exchange. /// @rsp_caps: Cached capabilities of responder. /// Received during GET_CAPABILITIES exchange. +/// @base_asym_alg: Asymmetric key algorithm for signature verification of +/// CHALLENGE_AUTH and MEASUREMENTS messages. +/// Selected by responder during NEGOTIATE_ALGORITHMS exchange. +/// @base_hash_alg: Hash algorithm for signature verification of +/// CHALLENGE_AUTH and MEASUREMENTS messages. +/// Selected by responder during NEGOTIATE_ALGORITHMS exchange. +/// @meas_hash_alg: Hash algorithm for measurement blocks. +/// Selected by responder during NEGOTIATE_ALGORITHMS exchange. +/// @base_asym_enc: Human-readable name of @base_asym_alg's signature encoding. +/// Passed to crypto subsystem when calling verify_signature(). +/// @sig_len: Signature length of @base_asym_alg (in bytes). +/// S or SigLen in SPDM specification. +/// @base_hash_alg_name: Human-readable name of @base_hash_alg. +/// Passed to crypto subsystem when calling crypto_alloc_shash() and +/// verify_signature(). +/// @base_hash_alg_name: Human-readable name of @base_hash_alg. +/// Passed to crypto subsystem when calling crypto_alloc_shash() and +/// verify_signature(). +/// @shash: Synchronous hash handle for @base_hash_alg computation. +/// @desc: Synchronous hash context for @base_hash_alg computation. +/// @hash_len: Hash length of @base_hash_alg (in bytes). +/// H in SPDM specification. /// /// `authenticated`: Whether device was authenticated successfully. #[expect(dead_code)] @@ -54,6 +82,19 @@ pub struct SpdmState { // Negotiated state pub(crate) version: u8, pub(crate) rsp_caps: u32, + pub(crate) base_asym_alg: u32, + pub(crate) base_hash_alg: u32, + pub(crate) meas_hash_alg: u32, + + /* Signature algorithm */ + base_asym_enc: &'static CStr, + sig_len: usize, + + /* Hash algorithm */ + base_hash_alg_name: &'static CStr, + pub(crate) shash: *mut bindings::crypto_shash, + pub(crate) desc: Option<&'static mut bindings::shash_desc>, + pub(crate) hash_len: usize, pub(crate) authenticated: bool, } @@ -76,6 +117,15 @@ pub(crate) fn new( validate, version: SPDM_MIN_VER, rsp_caps: 0, + base_asym_alg: 0, + base_hash_alg: 0, + meas_hash_alg: 0, + base_asym_enc: unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") }, + sig_len: 0, + base_hash_alg_name: unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") }, + shash: core::ptr::null_mut(), + desc: None, + hash_len: 0, authenticated: false, } } @@ -336,4 +386,161 @@ pub(crate) fn get_capabilities(&mut self) -> Result<(), Error> { Ok(()) } + + fn update_response_algs(&mut self) -> Result<(), Error> { + match self.base_asym_alg { + SPDM_ASYM_RSASSA_2048 => { + self.sig_len = 256; + self.base_asym_enc = CStr::from_bytes_with_nul(b"pkcs1\0")?; + } + SPDM_ASYM_RSASSA_3072 => { + self.sig_len = 384; + self.base_asym_enc = CStr::from_bytes_with_nul(b"pkcs1\0")?; + } + SPDM_ASYM_RSASSA_4096 => { + self.sig_len = 512; + self.base_asym_enc = CStr::from_bytes_with_nul(b"pkcs1\0")?; + } + SPDM_ASYM_ECDSA_ECC_NIST_P256 => { + self.sig_len = 64; + self.base_asym_enc = CStr::from_bytes_with_nul(b"p1363\0")?; + } + SPDM_ASYM_ECDSA_ECC_NIST_P384 => { + self.sig_len = 96; + self.base_asym_enc = CStr::from_bytes_with_nul(b"p1363\0")?; + } + SPDM_ASYM_ECDSA_ECC_NIST_P521 => { + self.sig_len = 132; + self.base_asym_enc = CStr::from_bytes_with_nul(b"p1363\0")?; + } + _ => { + pr_err!("Unknown asym algorithm\n"); + return Err(EINVAL); + } + } + + match self.base_hash_alg { + SPDM_HASH_SHA_256 => { + self.base_hash_alg_name = CStr::from_bytes_with_nul(b"sha256\0")?; + } + SPDM_HASH_SHA_384 => { + self.base_hash_alg_name = CStr::from_bytes_with_nul(b"sha384\0")?; + } + SPDM_HASH_SHA_512 => { + self.base_hash_alg_name = CStr::from_bytes_with_nul(b"sha512\0")?; + } + _ => { + pr_err!("Unknown hash algorithm\n"); + return Err(EINVAL); + } + } + + /* + * shash and desc allocations are reused for subsequent measurement + * retrieval, hence are not freed until spdm_reset(). + */ + self.shash = + unsafe { bindings::crypto_alloc_shash(self.base_hash_alg_name.as_char_ptr(), 0, 0) }; + if self.shash.is_null() { + return Err(ENOMEM); + } + + let desc_len = core::mem::size_of::() + + unsafe { bindings::crypto_shash_descsize(self.shash) } as usize; + + let mut desc_vec: KVec = KVec::with_capacity(desc_len, GFP_KERNEL)?; + // SAFETY: `desc_vec` is `desc_len` long + let desc_buf = unsafe { from_raw_parts_mut(desc_vec.as_mut_ptr(), desc_len) }; + + let desc = unsafe { + core::mem::transmute::<*mut c_void, &mut bindings::shash_desc>( + desc_buf.as_mut_ptr() as *mut c_void + ) + }; + desc.tfm = self.shash; + + self.desc = Some(desc); + + /* Used frequently to compute offsets, so cache H */ + self.hash_len = unsafe { bindings::crypto_shash_digestsize(self.shash) as usize }; + + if let Some(desc) = &mut self.desc { + unsafe { to_result(bindings::crypto_shash_init(*desc)) } + } else { + Err(ENOMEM) + } + } + + pub(crate) fn negotiate_algs(&mut self) -> Result<(), Error> { + let mut request = NegotiateAlgsReq::default(); + request.version = self.version; + + if self.version >= SPDM_VER_12 && (self.rsp_caps & SPDM_KEY_EX_CAP) == SPDM_KEY_EX_CAP { + request.other_params_support = SPDM_OPAQUE_DATA_FMT_GENERAL; + } + + // TODO support more algs + let reg_alg_entries = 0; + + let req_sz = core::mem::size_of::() + + core::mem::size_of::() * reg_alg_entries; + let rsp_sz = core::mem::size_of::() + + core::mem::size_of::() * reg_alg_entries; + + request.length = req_sz as u16; + request.param1 = reg_alg_entries as u8; + + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) }; + + let mut response_vec: KVec = KVec::with_capacity(rsp_sz, GFP_KERNEL)?; + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) }; + + let rc = self.spdm_exchange(request_buf, response_buf)?; + + if rc < (rsp_sz as i32) { + pr_err!("Truncated capabilities response\n"); + to_result(-(bindings::EIO as i32))?; + } + + // SAFETY: `rc` bytes where inserted to the raw pointer by spdm_exchange + unsafe { response_vec.set_len(rc as usize) }; + + let response: &mut NegotiateAlgsRsp = + Untrusted::new_mut(&mut response_vec).validate_mut()?; + + self.base_asym_alg = response.base_asym_sel; + self.base_hash_alg = response.base_hash_sel; + self.meas_hash_alg = response.measurement_hash_algo; + + if self.base_asym_alg & SPDM_ASYM_ALGOS == 0 || self.base_hash_alg & SPDM_HASH_ALGOS == 0 { + pr_err!("No common supported algorithms\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + // /* Responder shall select exactly 1 alg (SPDM 1.0.0 table 14) */ + if self.base_asym_alg.count_ones() != 1 + || self.base_hash_alg.count_ones() != 1 + || response.ext_asym_sel_count != 0 + || response.ext_hash_sel_count != 0 + || response.param1 > request.param1 + || response.other_params_sel != request.other_params_support + { + pr_err!("Malformed algorithms response\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + if self.rsp_caps & SPDM_MEAS_CAP_MASK == SPDM_MEAS_CAP_MASK + && (self.meas_hash_alg.count_ones() != 1 + || response.measurement_specification_sel != SPDM_MEAS_SPEC_DMTF) + { + pr_err!("Malformed algorithms response\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + self.update_response_algs()?; + + Ok(()) + } } diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs index cd792c46767a..036a077c71c3 100644 --- a/lib/rspdm/validator.rs +++ b/lib/rspdm/validator.rs @@ -7,7 +7,7 @@ //! Rust implementation of the DMTF Security Protocol and Data Model (SPDM) //! -use crate::bindings::{__IncompleteArrayField, __le16}; +use crate::bindings::{__IncompleteArrayField, __le16, __le32}; use crate::consts::SpdmErrorCode; use core::mem; use kernel::prelude::*; @@ -16,7 +16,10 @@ validate::{Unvalidated, Validate}, }; -use crate::consts::{SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_VERSION, SPDM_REQ_CAPS}; +use crate::consts::{ + SPDM_ASYM_ALGOS, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_VERSION, SPDM_HASH_ALGOS, + SPDM_MEAS_SPEC_DMTF, SPDM_NEGOTIATE_ALGS, SPDM_REQ_CAPS, +}; #[repr(C, packed)] pub(crate) struct SpdmHeader { @@ -205,3 +208,111 @@ fn validate(unvalidated: &mut Unvalidated>) -> Result Ok(rsp) } } + +#[repr(C, packed)] +pub(crate) struct RegAlg { + pub(crate) alg_type: u8, + pub(crate) alg_count: u8, + pub(crate) alg_supported: u16, + pub(crate) alg_external: __IncompleteArrayField<__le32>, +} + +#[repr(C, packed)] +pub(crate) struct NegotiateAlgsReq { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) length: u16, + pub(crate) measurement_specification: u8, + pub(crate) other_params_support: u8, + + pub(crate) base_asym_algo: u32, + pub(crate) base_hash_algo: u32, + + reserved1: [u8; 12], + + pub(crate) ext_asym_count: u8, + pub(crate) ext_hash_count: u8, + reserved2: u8, + pub(crate) mel_specification: u8, + + pub(crate) ext_asym: __IncompleteArrayField<__le32>, + pub(crate) ext_hash: __IncompleteArrayField<__le32>, + pub(crate) req_alg_struct: __IncompleteArrayField, +} + +impl Default for NegotiateAlgsReq { + fn default() -> Self { + NegotiateAlgsReq { + version: 0, + code: SPDM_NEGOTIATE_ALGS, + param1: 0, + param2: 0, + length: 0, + measurement_specification: SPDM_MEAS_SPEC_DMTF, + other_params_support: 0, + base_asym_algo: SPDM_ASYM_ALGOS.to_le(), + base_hash_algo: SPDM_HASH_ALGOS.to_le(), + reserved1: [0u8; 12], + ext_asym_count: 0, + ext_hash_count: 0, + reserved2: 0, + mel_specification: 0, + ext_asym: __IncompleteArrayField::new(), + ext_hash: __IncompleteArrayField::new(), + req_alg_struct: __IncompleteArrayField::new(), + } + } +} + +#[repr(C, packed)] +pub(crate) struct NegotiateAlgsRsp { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) length: u16, + pub(crate) measurement_specification_sel: u8, + pub(crate) other_params_sel: u8, + + pub(crate) measurement_hash_algo: u32, + pub(crate) base_asym_sel: u32, + pub(crate) base_hash_sel: u32, + + reserved1: [u8; 11], + + pub(crate) mel_specification_sel: u8, + pub(crate) ext_asym_sel_count: u8, + pub(crate) ext_hash_sel_count: u8, + reserved2: [u8; 2], + + pub(crate) ext_asym: __IncompleteArrayField<__le32>, + pub(crate) ext_hash: __IncompleteArrayField<__le32>, + pub(crate) req_alg_struct: __IncompleteArrayField, +} + +impl Validate<&mut Unvalidated>> for &mut NegotiateAlgsRsp { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `NegotiateAlgsRsp` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let rsp: &mut NegotiateAlgsRsp = unsafe { &mut *ptr }; + + rsp.base_asym_sel = rsp.base_asym_sel.to_le(); + rsp.base_hash_sel = rsp.base_hash_sel.to_le(); + rsp.measurement_hash_algo = rsp.measurement_hash_algo.to_le(); + + Ok(rsp) + } +} diff --git a/rust/bindgen_static_functions b/rust/bindgen_static_functions index ec48ad2e8c78..978276e17754 100644 --- a/rust/bindgen_static_functions +++ b/rust/bindgen_static_functions @@ -30,3 +30,8 @@ --allowlist-function copy_from_user --allowlist-function copy_to_user + +--allowlist-function crypto_shash_descsize +--allowlist-function crypto_shash_init +--allowlist-function crypto_shash_digestsize +--allowlist-function crypto_free_shash diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 42aa62f0c8f5..5ba1191429f8 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -6,6 +6,7 @@ * Sorted alphabetically. */ +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include From patchwork Thu Feb 27 03:09:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993666 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 D90431AF0BA; Thu, 27 Feb 2025 03:11:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625902; cv=none; b=UrbUD9Mat4HQ3jnmGyLyeXXTZR+tcophFK+FGh2dZ/9Uho0tFgHk+B1hiikgqPT9LWSC45e+2+JrAg9hak5mfiGiFZ+3hbuQ1zU8YNlOwjpP5o6YGFHtaE8yuFb70cPsKmM6h8Rj/ElrbO5UXEHgZ0v8b6LwNz2ewSCPcph7Z7Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625902; c=relaxed/simple; bh=xjXYpRdOJH3xqc+w5Sk610RABFY8qSV8xRa0fgEeVTo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aYg52b+8bTyxZoDRmu+8Ng4NjXQKat1AfB07EDMRltE0UEBo10sBdsQNkmiW+DwG9xFYhNx2o5dUhIziCrb+zHsDihkdQ+pmXrnORpdZj/7ZtZOjgWdmYRSTTM2SR1jWablp40S7ZV9Jw+kp5dV9EsnqyQznvgL/x3IF9bS0jDo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=luAdfp5J; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Zz6+Q4cN; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="luAdfp5J"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Zz6+Q4cN" Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id 9406D11401AB; Wed, 26 Feb 2025 22:11:39 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-05.internal (MEProxy); Wed, 26 Feb 2025 22:11:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625899; x= 1740712299; bh=vQ3zjvSsX16w4XFFO6FyrbKChsJWTWoMOKDjAuEvQZg=; b=l uAdfp5JEXhxLEj+qcifVLxeKHzlD2icytcuRoRsMq4U0Y4Swp8Nj4Z+g7SGQwwNq J044p4iTArNHtAGYxMtf/Puzfp4LS3hQfQnHV8Fcg3OIfWinjhE/TvgSf/6Cg4Cw Ee1lxIa7hJgQ6ULJXbypbjhT9WIeEelvqoOeJVqmDkJx2enXijf0Xv6eqtyEIKk7 Cqxxh74/HkvYyxhlOaORtFZru3uig68P+uRvc+qaFWMi5wFi+RyhCLu5dPMQwec5 Ix/Ttg8a9M5ORrCEG40n9nKrZLvvsxm3HCNj8eQJ55FVpHLa5FKiNKgjXoUoeYA5 NV0+9Mc1Dxj7KjjiZz2sA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625899; x=1740712299; bh=v Q3zjvSsX16w4XFFO6FyrbKChsJWTWoMOKDjAuEvQZg=; b=Zz6+Q4cNJKsrIsy+Z 3bml12EaUdUY7tu4A8osogbWoidd+9g2Mi/7KaIOPTW+MNBH73q5qgCzj0ZK+jZt UaFirC3XCfk9RsiLa+fhPeO8Qzl6mpr1ZQv3ZWON9HGggq7bSCZst/W94Yf5YKVU Fvg1h8liHaXhQu4apmeXkYSHAuWEHvP3NZVAC4HuW8Kg5pw0xFyDmBaMGawge6o1 UydwIqez9Akj7vCbJTu/7JB4Lbw6YxNlY0UeMXVfmRVOfkvSZjKjiv+ZSh4bSTo0 dpYn+DnbAXDdmxdiYxMFi/89CWmX8qNLuEPQTNZ5eR77T6sZIoSgTMkit5v2Gi4M VYy0w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:32 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 13/20] lib: rspdm: Support SPDM get_digests Date: Thu, 27 Feb 2025 13:09:45 +1000 Message-ID: <20250227030952.2319050-14-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Signed-off-by: Alistair Francis --- lib/rspdm/consts.rs | 4 ++ lib/rspdm/lib.rs | 4 ++ lib/rspdm/state.rs | 89 ++++++++++++++++++++++++++++++++++++++++-- lib/rspdm/validator.rs | 52 +++++++++++++++++++++++- 4 files changed, 144 insertions(+), 5 deletions(-) diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs index d2f245c858cc..9714fa52e2be 100644 --- a/lib/rspdm/consts.rs +++ b/lib/rspdm/consts.rs @@ -16,6 +16,8 @@ pub(crate) const SPDM_VER_12: u8 = 0x12; pub(crate) const SPDM_VER_13: u8 = 0x13; +pub(crate) const SPDM_SLOTS: usize = 8; + pub(crate) const SPDM_MIN_VER: u8 = SPDM_VER_10; pub(crate) const SPDM_MAX_VER: u8 = SPDM_VER_13; @@ -92,6 +94,8 @@ pub(crate) enum SpdmErrorCode { pub(crate) const SPDM_HASH_SHA_384: u32 = 1 << 1; pub(crate) const SPDM_HASH_SHA_512: u32 = 1 << 2; +pub(crate) const SPDM_GET_DIGESTS: u8 = 0x81; + #[cfg(CONFIG_CRYPTO_RSA)] pub(crate) const SPDM_ASYM_RSA: u32 = SPDM_ASYM_RSASSA_2048 | SPDM_ASYM_RSASSA_3072 | SPDM_ASYM_RSASSA_4096; diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index 5eee5116d791..bf5f7c72f885 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -122,6 +122,10 @@ return e.to_errno() as c_int; } + if let Err(e) = state.get_digests() { + return e.to_errno() as c_int; + } + 0 } diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index 0aff45339e0b..7889214c6aa7 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -23,11 +23,11 @@ SPDM_ASYM_RSASSA_4096, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_HASH_ALGOS, SPDM_HASH_SHA_256, SPDM_HASH_SHA_384, SPDM_HASH_SHA_512, SPDM_KEY_EX_CAP, SPDM_MAX_VER, SPDM_MEAS_CAP_MASK, SPDM_MEAS_SPEC_DMTF, SPDM_MIN_DATA_TRANSFER_SIZE, SPDM_MIN_VER, SPDM_OPAQUE_DATA_FMT_GENERAL, - SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, + SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_SLOTS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, }; use crate::validator::{ - GetCapabilitiesReq, GetCapabilitiesRsp, GetVersionReq, GetVersionRsp, NegotiateAlgsReq, - NegotiateAlgsRsp, RegAlg, SpdmErrorRsp, SpdmHeader, + GetCapabilitiesReq, GetCapabilitiesRsp, GetDigestsReq, GetDigestsRsp, GetVersionReq, + GetVersionRsp, NegotiateAlgsReq, NegotiateAlgsRsp, RegAlg, SpdmErrorRsp, SpdmHeader, }; /// The current SPDM session state for a device. Based on the @@ -54,6 +54,10 @@ /// Selected by responder during NEGOTIATE_ALGORITHMS exchange. /// @meas_hash_alg: Hash algorithm for measurement blocks. /// Selected by responder during NEGOTIATE_ALGORITHMS exchange. +/// @supported_slots: Bitmask of responder's supported certificate slots. +/// Received during GET_DIGESTS exchange (from SPDM 1.3). +/// @provisioned_slots: Bitmask of responder's provisioned certificate slots. +/// Received during GET_DIGESTS exchange. /// @base_asym_enc: Human-readable name of @base_asym_alg's signature encoding. /// Passed to crypto subsystem when calling verify_signature(). /// @sig_len: Signature length of @base_asym_alg (in bytes). @@ -68,6 +72,9 @@ /// @desc: Synchronous hash context for @base_hash_alg computation. /// @hash_len: Hash length of @base_hash_alg (in bytes). /// H in SPDM specification. +/// @slot: Certificate chain in each of the 8 slots. NULL pointer if a slot is +/// not populated. Prefixed by the 4 + H header per SPDM 1.0.0 table 15. +/// @slot_sz: Certificate chain size (in bytes). /// /// `authenticated`: Whether device was authenticated successfully. #[expect(dead_code)] @@ -85,6 +92,8 @@ pub struct SpdmState { pub(crate) base_asym_alg: u32, pub(crate) base_hash_alg: u32, pub(crate) meas_hash_alg: u32, + pub(crate) supported_slots: u8, + pub(crate) provisioned_slots: u8, /* Signature algorithm */ base_asym_enc: &'static CStr, @@ -97,6 +106,10 @@ pub struct SpdmState { pub(crate) hash_len: usize, pub(crate) authenticated: bool, + + // Certificates + pub(crate) slot: [Option>; SPDM_SLOTS], + slot_sz: [usize; SPDM_SLOTS], } impl SpdmState { @@ -120,6 +133,8 @@ pub(crate) fn new( base_asym_alg: 0, base_hash_alg: 0, meas_hash_alg: 0, + supported_slots: 0, + provisioned_slots: 0, base_asym_enc: unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") }, sig_len: 0, base_hash_alg_name: unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") }, @@ -127,6 +142,8 @@ pub(crate) fn new( desc: None, hash_len: 0, authenticated: false, + slot: [const { None }; SPDM_SLOTS], + slot_sz: [0; SPDM_SLOTS], } } @@ -543,4 +560,70 @@ pub(crate) fn negotiate_algs(&mut self) -> Result<(), Error> { Ok(()) } + + pub(crate) fn get_digests(&mut self) -> Result<(), Error> { + let mut request = GetDigestsReq::default(); + request.version = self.version; + + let req_sz = core::mem::size_of::(); + let rsp_sz = core::mem::size_of::() + SPDM_SLOTS * self.hash_len; + + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) }; + + let mut response_vec: KVec = KVec::with_capacity(rsp_sz, GFP_KERNEL)?; + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) }; + + let rc = self.spdm_exchange(request_buf, response_buf)?; + + if rc < (core::mem::size_of::() as i32) { + pr_err!("Truncated digests response\n"); + to_result(-(bindings::EIO as i32))?; + } + + // SAFETY: `rc` bytes where inserted to the raw pointer by spdm_exchange + unsafe { response_vec.set_len(rc as usize) }; + + let response: &mut GetDigestsRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + + if rc + < (core::mem::size_of::() + + response.param2.count_ones() as usize * self.hash_len) as i32 + { + pr_err!("Truncated digests response\n"); + to_result(-(bindings::EIO as i32))?; + } + + let mut deprovisioned_slots = self.provisioned_slots & !response.param2; + while (deprovisioned_slots.trailing_zeros() as usize) < SPDM_SLOTS { + let slot = deprovisioned_slots.trailing_zeros() as usize; + self.slot[slot] = None; + self.slot_sz[slot] = 0; + deprovisioned_slots &= !(1 << slot); + } + + self.provisioned_slots = response.param2; + if self.provisioned_slots == 0 { + pr_err!("No certificates provisioned\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + if self.version >= 0x13 && (response.param2 & !response.param1 != 0) { + pr_err!("Malformed digests response\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + let supported_slots = if self.version >= 0x13 { + response.param1 + } else { + 0xFF + }; + + if self.supported_slots != supported_slots { + self.supported_slots = supported_slots; + } + + Ok(()) + } } diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs index 036a077c71c3..2150a23997db 100644 --- a/lib/rspdm/validator.rs +++ b/lib/rspdm/validator.rs @@ -17,8 +17,8 @@ }; use crate::consts::{ - SPDM_ASYM_ALGOS, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_VERSION, SPDM_HASH_ALGOS, - SPDM_MEAS_SPEC_DMTF, SPDM_NEGOTIATE_ALGS, SPDM_REQ_CAPS, + SPDM_ASYM_ALGOS, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_DIGESTS, SPDM_GET_VERSION, + SPDM_HASH_ALGOS, SPDM_MEAS_SPEC_DMTF, SPDM_NEGOTIATE_ALGS, SPDM_REQ_CAPS, }; #[repr(C, packed)] @@ -316,3 +316,51 @@ fn validate(unvalidated: &mut Unvalidated>) -> Result Ok(rsp) } } + +#[repr(C, packed)] +pub(crate) struct GetDigestsReq { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, +} + +impl Default for GetDigestsReq { + fn default() -> Self { + GetDigestsReq { + version: 0, + code: SPDM_GET_DIGESTS, + param1: 0, + param2: 0, + } + } +} + +#[repr(C, packed)] +pub(crate) struct GetDigestsRsp { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) digests: __IncompleteArrayField, +} + +impl Validate<&mut Unvalidated>> for &mut GetDigestsRsp { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `GetDigestsRsp` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let rsp: &mut GetDigestsRsp = unsafe { &mut *ptr }; + + Ok(rsp) + } +} From patchwork Thu Feb 27 03:09:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993667 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 EF4731C6FF8; Thu, 27 Feb 2025 03:11:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625909; cv=none; b=GTuzWaHlgwiF+KF8rR6ho7rcvcZQpn6Tr0We+wSLd1lJn5zlxZcAaOjeTaGwVg5oRhp0et2j/MODXty5agrO18P/vRmRxUkSFCeEeNJ2BJIYFwvAHQnYC+d3rKmySG9JneWqHspBv73vkOVvx/pUgOel8s8zFplSNhFpLJ8pNNs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625909; c=relaxed/simple; bh=/ac9/4dnsyJcRleWLsYsLU2zT9prStc39+qtMZANcd8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aCu/pqaY7VnOjtszivu2BnYeGp4h+FC78fIi+ZDtT8EEMQsfOqeo9HVSbo5501BjTn0gDX1wjaDDTyQ62PQNiNZ8tx5xucCvy1Qa/0a/BDmzpJAgE549itNH6C8AKD5l8FA+o7RuDlMuXloNmOJ6cFQKYhA2FTvWnMp9lBJgF00= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=fMovNesD; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=fB97Y/Xo; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="fMovNesD"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="fB97Y/Xo" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfout.stl.internal (Postfix) with ESMTP id 7A91211401A3; Wed, 26 Feb 2025 22:11:46 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:11:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625906; x= 1740712306; bh=AknGaepVfMtNBcp7Xo/wA1SJO6y/hq/JaQGUv26u+4A=; b=f MovNesDWjttzm17FUyK0gXJ9mP/kvRZL9RSvTXYEYkAnnrPkldIniU7qzyS/GXvY JWQ6Xaa2zoMu+JxwcDmqWh8WT/mL20CS/QUcQK7vTCoKj9KSA3R6QlPoPA8LmG2D SpKDaAftlkC7nNhTlfCvFHON4ZD9dXr49p+w8yiwjwHttRO0d9xfhUxs2xk5h4BG VtnVA84eBSBilQCGLyYjupgKaPaib7ISbaXdEOBNq5+674i47OgnOtSoITPzwMJf Ksj9+E72UfnbVeDXuFv9nu6t99xdH7DA4L/pLBHqa9VGsskaSEe+CgWe/dOY4/Ym gfmdXLGnePxbPzp5neTHg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625906; x=1740712306; bh=A knGaepVfMtNBcp7Xo/wA1SJO6y/hq/JaQGUv26u+4A=; b=fB97Y/XocPelnG3MF Dj4O13V2QLI0q4k0BvWyMy3GhvFGfXyfOaQPKYgmTSWVfDXsRjwBxXqRcGC+N8Ms JePu5F7ZCG4ag4i1PSCNBjzmYWjrnGfauByRH1qXVdoBDg1d7SEe87P0MDps4Ul3 HEx8PqmMOmMTVWLN3sj2JmpMKz4zYQzTSxkmy0wXp0f3B3OmfcwCvypZr/C0SevH yzQM0TmOisvqoYOT6tIkajjHNToEqlBWnia1PYTJAhMqehW0ckBrcCk0PhuQfEFe nAeD10YeBeDkIYx98RcwMjQsMkpq3vg+mzOtxWEsIYa5PwstE5H5s0l5Acve9uTS SyLoQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpedvhefhfeevffelhffgjeeg gefhteelieekudeiieeiteffudetheeihfdukeehleenucffohhmrghinhepphhorhhtih honhgplhgvnhhgthhhrdhtohdprhgvmhgrihhnuggvrhgplhgvnhhgthhhrdhtohenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrg hirhesrghlihhsthgrihhrvdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgep shhmthhpohhuthdprhgtphhtthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvg hlrdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhn vghlrdhorhhgpdhrtghpthhtoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtth hopehlihhnuhigqdhptghisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohep sghhvghlghgrrghssehgohhoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnh drtggrmhgvrhhonheshhhurgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhr qdhlihhnuhigsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmse hlihhnuhigqdhfohhunhgurghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhf vghnghesghhmrghilhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:40 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 14/20] lib: rspdm: Support SPDM get_certificate Date: Thu, 27 Feb 2025 13:09:46 +1000 Message-ID: <20250227030952.2319050-15-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Signed-off-by: Alistair Francis --- lib/rspdm/consts.rs | 2 + lib/rspdm/lib.rs | 11 ++++ lib/rspdm/state.rs | 123 ++++++++++++++++++++++++++++++++++++++++- lib/rspdm/validator.rs | 64 ++++++++++++++++++++- 4 files changed, 196 insertions(+), 4 deletions(-) diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs index 9714fa52e2be..ffaf36ec583b 100644 --- a/lib/rspdm/consts.rs +++ b/lib/rspdm/consts.rs @@ -96,6 +96,8 @@ pub(crate) enum SpdmErrorCode { pub(crate) const SPDM_GET_DIGESTS: u8 = 0x81; +pub(crate) const SPDM_GET_CERTIFICATE: u8 = 0x82; + #[cfg(CONFIG_CRYPTO_RSA)] pub(crate) const SPDM_ASYM_RSA: u32 = SPDM_ASYM_RSASSA_2048 | SPDM_ASYM_RSASSA_3072 | SPDM_ASYM_RSASSA_4096; diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index bf5f7c72f885..1535e3a69518 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -126,6 +126,17 @@ return e.to_errno() as c_int; } + let mut provisioned_slots = state.provisioned_slots; + while (provisioned_slots as usize) > 0 { + let slot = provisioned_slots.trailing_zeros() as u8; + + if let Err(e) = state.get_certificate(slot) { + return e.to_errno() as c_int; + } + + provisioned_slots &= !(1 << slot); + } + 0 } diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index 7889214c6aa7..ae259623fe50 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -26,8 +26,9 @@ SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_SLOTS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, }; use crate::validator::{ - GetCapabilitiesReq, GetCapabilitiesRsp, GetDigestsReq, GetDigestsRsp, GetVersionReq, - GetVersionRsp, NegotiateAlgsReq, NegotiateAlgsRsp, RegAlg, SpdmErrorRsp, SpdmHeader, + GetCapabilitiesReq, GetCapabilitiesRsp, GetCertificateReq, GetCertificateRsp, GetDigestsReq, + GetDigestsRsp, GetVersionReq, GetVersionRsp, NegotiateAlgsReq, NegotiateAlgsRsp, RegAlg, + SpdmErrorRsp, SpdmHeader, }; /// The current SPDM session state for a device. Based on the @@ -112,6 +113,14 @@ pub struct SpdmState { slot_sz: [usize; SPDM_SLOTS], } +#[repr(C, packed)] +pub(crate) struct SpdmCertChain { + length: u16, + _reserved: [u8; 2], + root_hash: bindings::__IncompleteArrayField, + certificates: bindings::__IncompleteArrayField, +} + impl SpdmState { pub(crate) fn new( dev: *mut bindings::device, @@ -626,4 +635,114 @@ pub(crate) fn get_digests(&mut self) -> Result<(), Error> { Ok(()) } + + fn get_cert_exchange( + &mut self, + request_buf: &mut [u8], + response_vec: &mut KVec, + rsp_sz: usize, + ) -> Result<&mut GetCertificateRsp, Error> { + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) }; + + let rc = self.spdm_exchange(request_buf, response_buf)?; + + if rc < (core::mem::size_of::() as i32) { + pr_err!("Truncated certificate response\n"); + to_result(-(bindings::EIO as i32))?; + } + + // SAFETY: `rc` bytes where inserted to the raw pointer by spdm_exchange + unsafe { response_vec.set_len(rc as usize) }; + + let response: &mut GetCertificateRsp = Untrusted::new_mut(response_vec).validate_mut()?; + + if rc + < (core::mem::size_of::() + response.portion_length as usize) as i32 + { + pr_err!("Truncated certificate response\n"); + to_result(-(bindings::EIO as i32))?; + } + + Ok(response) + } + + pub(crate) fn get_certificate(&mut self, slot: u8) -> Result<(), Error> { + let mut request = GetCertificateReq::default(); + request.version = self.version; + request.param1 = slot; + + let req_sz = core::mem::size_of::(); + let rsp_sz = ((core::mem::size_of::() + 0xffff) as u32) + .min(self.transport_sz) as usize; + + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) }; + + let mut response_vec: KVec = KVec::with_capacity(rsp_sz, GFP_KERNEL)?; + + request.offset = 0; + request.length = (rsp_sz - core::mem::size_of::()).to_le() as u16; + + let response = self.get_cert_exchange(request_buf, &mut response_vec, rsp_sz)?; + + let total_cert_len = + ((response.portion_length + response.remainder_length) & 0xFFFF) as usize; + + let mut certs_buf: KVec = KVec::new(); + + certs_buf.extend_from_slice( + &response_vec[8..(8 + response.portion_length as usize)], + GFP_KERNEL, + )?; + + let mut offset: usize = response.portion_length as usize; + let mut remainder_length = response.remainder_length as usize; + + while remainder_length > 0 { + request.offset = offset.to_le() as u16; + request.length = (remainder_length + .min(rsp_sz - core::mem::size_of::())) + .to_le() as u16; + + let response = self.get_cert_exchange(request_buf, &mut response_vec, rsp_sz)?; + + if response.portion_length == 0 + || (response.param1 & 0xF) != slot + || offset as u16 + response.portion_length + response.remainder_length + != total_cert_len as u16 + { + pr_err!("Malformed certificate response\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + certs_buf.extend_from_slice( + &response_vec[8..(8 + response.portion_length as usize)], + GFP_KERNEL, + )?; + offset += response.portion_length as usize; + remainder_length = response.remainder_length as usize; + } + + let header_length = core::mem::size_of::() + self.hash_len; + + let ptr = certs_buf.as_mut_ptr(); + // SAFETY: `SpdmCertChain` is repr(C) and packed, so we can convert it from a slice + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let certs: &mut SpdmCertChain = unsafe { &mut *ptr }; + + if total_cert_len < header_length + || total_cert_len != usize::from_le(certs.length as usize) + || total_cert_len != certs_buf.len() + { + pr_err!("Malformed certificate chain in slot {slot}\n"); + to_result(-(bindings::EPROTO as i32))?; + } + + self.slot_sz[slot as usize] = total_cert_len; + self.slot[slot as usize] = Some(certs_buf); + + Ok(()) + } } diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs index 2150a23997db..a8bc3378676f 100644 --- a/lib/rspdm/validator.rs +++ b/lib/rspdm/validator.rs @@ -17,8 +17,9 @@ }; use crate::consts::{ - SPDM_ASYM_ALGOS, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_DIGESTS, SPDM_GET_VERSION, - SPDM_HASH_ALGOS, SPDM_MEAS_SPEC_DMTF, SPDM_NEGOTIATE_ALGS, SPDM_REQ_CAPS, + SPDM_ASYM_ALGOS, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_CERTIFICATE, + SPDM_GET_DIGESTS, SPDM_GET_VERSION, SPDM_HASH_ALGOS, SPDM_MEAS_SPEC_DMTF, SPDM_NEGOTIATE_ALGS, + SPDM_REQ_CAPS, }; #[repr(C, packed)] @@ -364,3 +365,62 @@ fn validate(unvalidated: &mut Unvalidated>) -> Result Ok(rsp) } } + +#[repr(C, packed)] +pub(crate) struct GetCertificateReq { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) offset: u16, + pub(crate) length: u16, +} + +impl Default for GetCertificateReq { + fn default() -> Self { + GetCertificateReq { + version: 0, + code: SPDM_GET_CERTIFICATE, + param1: 0, + param2: 0, + offset: 0, + length: 0, + } + } +} + +#[repr(C, packed)] +pub(crate) struct GetCertificateRsp { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) portion_length: u16, + pub(crate) remainder_length: u16, + + pub(crate) cert_chain: __IncompleteArrayField, +} + +impl Validate<&mut Unvalidated>> for &mut GetCertificateRsp { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `GetCertificateRsp` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let rsp: &mut GetCertificateRsp = unsafe { &mut *ptr }; + + rsp.portion_length = rsp.portion_length.to_le(); + rsp.remainder_length = rsp.remainder_length.to_le(); + + Ok(rsp) + } +} From patchwork Thu Feb 27 03:09:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993668 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 8CF741CCB4A; Thu, 27 Feb 2025 03:11:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625918; cv=none; b=PMtOMV1rGB72QKCUm1d0MaScxxKxJMgC167CG47ji3iJg37Owa99mrN+hu/6uF8kBk3cvZHFdZ16TNxHydYvgrenWMfn6RMiJwccxLbeVZJNb3k+41usLRe52JaLnSer5acHbPHiEKBhDPyKh/R63lMLsWnDOIgg8t9dHiah70U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625918; c=relaxed/simple; bh=kdEKjcv9tLEOlyxEKbgWiMdvqbaA3tcI1a3VIRlNCWg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=b9FyHpri8bM+69Qi3CaghJEfe1FFVAmyPe2NTSu6xiDuhxcDH3xkgwZljg9NEOnw/GmrjE6+C7Wf7OARX2yMAdoqj+QMbEkSi9IWOk3m9BPzWnKqIC+FOxtBMIUZECHrblk0Hc1wDxM/8fZpDIsZsMBAdCCsiopDC8RXX6RS9lI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=jMBhHwdK; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=mntzwzeK; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="jMBhHwdK"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="mntzwzeK" Received: from phl-compute-04.internal (phl-compute-04.phl.internal [10.202.2.44]) by mailfhigh.stl.internal (Postfix) with ESMTP id 77B632540099; Wed, 26 Feb 2025 22:11:53 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Wed, 26 Feb 2025 22:11:54 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625913; x= 1740712313; bh=ah6y+4h59cjSbt/gz1fqku9aOGTqXcZ3bO/mST1W1Pc=; b=j MBhHwdKeSzTbXD2YvD4zHKODKZuNAVGQKmZ/8VUOtF0+pw5yrwcj/8lLI0jnabY3 ezRi6jDRDp7IdDFTMgC7J1YHf02Oh+19ZKLDDR7oE7iY7P3qx0YghBVpCQHBMHkg BrYzCUu3NUupopkzfEodE3ijSU02EaJVFTBJEDWDmZ/xnbRatnhcToZJdHsfxRlb NA+03PRyxpJakcio8aV2zOi3mH/DWpOUXCxgj77M38xj3azvblrbu1gSTpmAqKnw 1Gqjck9fgTStGoEzYIUv5Q50jN5QkjNpDZfhSyNyTicNI5tbxD/fZO9h2FU3zYKA T7765NHw6jgt8PfvS5jcQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625913; x=1740712313; bh=a h6y+4h59cjSbt/gz1fqku9aOGTqXcZ3bO/mST1W1Pc=; b=mntzwzeKhjdgfuMZV D/1RCghEYniSW6KGHhDrIieMJKHx4a4TcZwnnwQ8JYTpj4zcxY3YPeDezTNinVGK k1R89Z1htwAahJwqly55fVWnDSqj+UQEbCQ6weudifVTtenXDdweA99+OZ6WSbxc sXyiT0w8fp+4qufeKEHJ5HqdF53BNTFsuA/5VFBlsmWxRs46h/hu5NDxU7HHd9QU 9gyjeALaevjn4ih/RjpkKHefNwUl2eNEgW55+AyhXJhr4tIcjkq39Gtcg68bvQmB jQpbQpEy9yO4yB9o/GnAJnhk38pZ88s+IIg9KHEcGST3RM/7GKK2wtk6u4JsjqIA LHmdw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:47 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 15/20] crypto: asymmetric_keys - Load certificate parsing early in boot Date: Thu, 27 Feb 2025 13:09:47 +1000 Message-ID: <20250227030952.2319050-16-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Work is ongoing to support PCIe device attestation and authentication. As part of this a PCIe device will provide a X.509 certificate chain via the SPDM protocol to the kernel. Linux should verify the chain before enabling the device, which means we need the certificate store ready before arch initilisation (where PCIe init happens). Move the certificate and keyring init to postcore to ensure it's loaded before PCIe devices. This patch enables X.509 certificate parsing and asymmetric key support early in the boot process so that it can be used by the key store and SPDM to verify the certificate chain provided by a PCIe device via SPDM before we enable it. Signed-off-by: Alistair Francis --- crypto/asymmetric_keys/asymmetric_type.c | 2 +- crypto/asymmetric_keys/x509_public_key.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index ba2d9d1ea235..44ebae5c059c 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -671,5 +671,5 @@ static void __exit asymmetric_key_cleanup(void) unregister_key_type(&key_type_asymmetric); } -module_init(asymmetric_key_init); +postcore_initcall(asymmetric_key_init); module_exit(asymmetric_key_cleanup); diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 8409d7d36cb4..997f3e7910d8 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -246,7 +246,7 @@ static void __exit x509_key_exit(void) unregister_asymmetric_key_parser(&x509_key_parser); } -module_init(x509_key_init); +postcore_initcall(x509_key_init); module_exit(x509_key_exit); MODULE_DESCRIPTION("X.509 certificate parser"); From patchwork Thu Feb 27 03:09:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993669 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 60DBF1A5BBC; Thu, 27 Feb 2025 03:12:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625922; cv=none; b=pncyGwpP9/3IDrkN24wp+hrGgasre468uHF1MTk84/v7hBQ7qgsuN4ifRucEpLERCOOGAUk4CPObZdxptp/EQwOSmBOLQtTinxJCPAvXPQW7COYk6RXLBb7pO1z3CJGmdD4ZgCsPrSqhe6NTVCxWXzCvFIlkekzZeB1gmMAiOII= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625922; c=relaxed/simple; bh=GTfEGM6C7u682dS5iVaYCUXbIIFqCwwWGzke2ksc1JM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X99njipnyrhuLdDRR2/OB8DuF1JxKUfJ8ivVb0ZtETYpJpD9AhK4u90JVBEV1c+SnCboSdRcS/NV7coj7w5Xp1L8SHkTDFEtRGtFhLSTI+oVEUV8R333WXhy121v9bTvQkAbzdc0hkmoP4PhgLw8qU7SdZPHe/QZuBi/7YsOJTM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=UaS0wvJl; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=GTFukQij; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="UaS0wvJl"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="GTFukQij" Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfout.stl.internal (Postfix) with ESMTP id 4B0CE11401A7; Wed, 26 Feb 2025 22:12:00 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Wed, 26 Feb 2025 22:12:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625920; x= 1740712320; bh=//SgTkBvq5QqRs/XyLf61Um2H+GXIpwL4t51TxO5nWw=; b=U aS0wvJljS6vQ5FcdZRmy7w+rC7Exz1qOHi/BcLJih3i+2O5XhPV13DzCFR9zplsQ TSKuLmepM4wMT8hG6Hd5T7NjxSsbpDgbHQcGcWjmdFvJqpkfu9Mc4eDXutI0jgTh kKCArts+Ljju77Wf+ec72PBqZuoOzc2ju4imc3Ost0dAGAOJtAahwieEjRorMF7l OqWxYzxxd0D0PriiDR77dR09aqaKsTznU6uuK83hzHv44j7Kvw4T8Y2A6DIfitA9 szuDogbavCI33WnYsr9tepaedDk5Zj3AoQkIfeCADnlk5ARh+pyir7xj0Vw7fjV+ 48LIlb6EYPoG4EF4PWxsw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625920; x=1740712320; bh=/ /SgTkBvq5QqRs/XyLf61Um2H+GXIpwL4t51TxO5nWw=; b=GTFukQijs0Mh3VztB qD2z709nTVT3RCDpJVzqo3IyIMjETX5Zn72wLJolmSlfxuggY4cKMpAPVvC5gN5j et3kJL1BUmNVRnvfjxyS1jIRvKYEZ13k5q+LHRjtw+pQlo03+DKyY0/mEodbTOW6 uve0QyCZ5RipXIKkM0e1EIYfW+oXbEulvV5wgkMoeKpB/kKsMwvcLLZhfCexEqbY VlgPLigVnWuo3uwFVbCmgz/jtX46ZsH5re/hIjQP80qbWPoBcS+EQQiOyMRLBbT1 T0EejzXVU4oaeclYrb+TvCVzPP9Xn/pwoXiDjJAEp5j4oeo99qkZAhHIwxy4ZQnx qGDCg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:11:54 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 16/20] KEYS: Load keyring and certificates early in boot Date: Thu, 27 Feb 2025 13:09:48 +1000 Message-ID: <20250227030952.2319050-17-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Work is ongoing to support PCIe device attestation and authentication. As part of this a PCIe device will provide a certificate chain via the SPDM protocol to the kernel. Linux should verify the chain before enabling the device, which means we need the certificate store ready before arch initilisation (where PCIe init happens). Move the certificate and keyring init to postcore to ensure it's loaded before PCIe devices. This allows us to verify the certificate chain provided by a PCIe device via SPDM before we enable it. Signed-off-by: Alistair Francis --- certs/system_keyring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 9de610bf1f4b..f3d8ea4f70b4 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -260,7 +260,7 @@ static __init int system_trusted_keyring_init(void) /* * Must be initialised before we try and load the keys into the keyring. */ -device_initcall(system_trusted_keyring_init); +postcore_initcall(system_trusted_keyring_init); __init int load_module_cert(struct key *keyring) { @@ -293,7 +293,7 @@ static __init int load_system_certificate_list(void) return x509_load_certificate_list(p, size, builtin_trusted_keys); } -late_initcall(load_system_certificate_list); +postcore_initcall(load_system_certificate_list); #ifdef CONFIG_SYSTEM_DATA_VERIFICATION From patchwork Thu Feb 27 03:09:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993670 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 5E9B81B0409; Thu, 27 Feb 2025 03:12:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625929; cv=none; b=ltdiyBBvLalg8gJgMnUyd4BAq+5OuDvnbpARE5MQL8UUtiaJLFXVXBpL4dA3CiCI7G2/4BYJyih/PvNzBLdla0RaouNLMeJsL2e39o+p+PuqN9440gCxh6TT+6JZFW1jTXdEnCnBmQfqtO1oLh0p24WK+DW0CkZ4aI9LvgJplJc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625929; c=relaxed/simple; bh=U/g3eQTMR1Nrt00+4SlWpupeJ4a45LyJy/RDOh1OZSQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CdRPxMvHrH0JMXOAvBeRE3dmbg6v+vxvXv/cFP6ZPeqkuoGnMAVjSF19rmjPVjaLy4ulXJx+lL9xeYZkTZW+diqghP+mURWX6O+i7TaCL24JZDcrGkKJy02rDJ2kL8cJjLQqD0WBd0oTbrvU6tVSOTV7ewQxb6au68UO2cwy8jk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=kpGZ1x4P; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=jpMwrTHk; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="kpGZ1x4P"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="jpMwrTHk" Received: from phl-compute-13.internal (phl-compute-13.phl.internal [10.202.2.53]) by mailfhigh.stl.internal (Postfix) with ESMTP id 13D1F25400E5; Wed, 26 Feb 2025 22:12:07 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-13.internal (MEProxy); Wed, 26 Feb 2025 22:12:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625926; x= 1740712326; bh=ETaO0MKiUxQhhDGFr/kw3wzQd9hq+z6Q0USbIeJj8PY=; b=k pGZ1x4PP2rYlQIPgW9ynZ9ACly5u4HrHbEYIV/n+15G4nHaikHzg9pjJsfUhQ/yK eNWIN8+W2C4wQO2ao6JbG+tVlO9zSCzXvPs7J1XJz3BvNdse//Gxt/gjzkF3XuDC JAlPCYwBvKLQBtHVOnUlNBRBixCqJ6QvV8erojAaunTemvGF73Q8NzT5N/4zJe8z 7IJBldmPNvGrRiOl3zGx1ZSZ1ub7dFKZf7JlRz6jC9JMbefZe4+uPV9lNS1npLDt HLR/s2lmsj87mxWIvusYntiDR7u9A6FtVSwjtGBq4OYbFgLq8srhSQJXIZY9krNI ZVrOqE4Xd42hxvoIo4zXw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625926; x=1740712326; bh=E TaO0MKiUxQhhDGFr/kw3wzQd9hq+z6Q0USbIeJj8PY=; b=jpMwrTHkEfnfYgv76 NkeffH3wc9afCMStkrPHdgcqgA0oZBYMjPC6Bn7pNAVE3ir6+OHbSOKfgfvHsFmy NA+lN69Ys7y7tVsl7+9tTRnpSOBZ5GEee2axp+tv669e7TZ32rR/RuKrYGcf+ZZU bOpyQWOylmiCMwFaZdLO2WTsPkXANHzwdTa/W+fl8wU6FVRc7xyHhmqJV4/Cy8CJ PwMBhFqrnLaJtOw9rOmTlvd9rb3myfiVQv6DSg+xJII1MI89JnSPo5dYho6914Mw CgrPBmvMEF4u2/XxY3pBZNVdWd8vNxUUYfBgFj3pAc5HzdKwbwErjzsSgALuX5Hg S9rYg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:12:01 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 17/20] PCI/CMA: Support built in X.509 certificates Date: Thu, 27 Feb 2025 13:09:49 +1000 Message-ID: <20250227030952.2319050-18-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Support building the X.509 certificates into the CMA certificate store. This allows certificates to be built into the kernel which can be used to authenticate PCIe devices via SPDM. Signed-off-by: Alistair Francis --- drivers/pci/cma.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c index 59558714f143..381d8f32a5a7 100644 --- a/drivers/pci/cma.c +++ b/drivers/pci/cma.c @@ -24,6 +24,10 @@ /* Keyring that userspace can poke certs into */ static struct key *pci_cma_keyring; +extern __initconst const u8 system_certificate_list[]; +extern __initconst const unsigned long system_certificate_list_size; +extern __initconst const unsigned long module_cert_size; + /* * The spdm_requester.c library calls pci_cma_validate() to check requirements * for Leaf Certificates per PCIe r6.1 sec 6.31.3. @@ -222,8 +226,31 @@ void pci_cma_destroy(struct pci_dev *pdev) spdm_destroy(pdev->spdm_state); } +/* + * Load the compiled-in list of X.509 certificates. + */ +static int load_system_certificate_list(void) +{ + const u8 *p; + unsigned long size; + + pr_notice("Loading compiled-in X.509 certificates for CMA\n"); + +#ifdef CONFIG_MODULE_SIG + p = system_certificate_list; + size = system_certificate_list_size; +#else + p = system_certificate_list + module_cert_size; + size = system_certificate_list_size - module_cert_size; +#endif + + return x509_load_certificate_list(p, size, pci_cma_keyring); +} + __init static int pci_cma_keyring_init(void) { + int rc; + pci_cma_keyring = keyring_alloc(".cma", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), (KEY_POS_ALL & ~KEY_POS_SETATTR) | @@ -236,6 +263,10 @@ __init static int pci_cma_keyring_init(void) return PTR_ERR(pci_cma_keyring); } + rc = load_system_certificate_list(); + if (rc) + return rc; + return 0; } arch_initcall(pci_cma_keyring_init); From patchwork Thu Feb 27 03:09:50 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993671 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 34269187FEC; Thu, 27 Feb 2025 03:12:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625936; cv=none; b=gURNA93n6SHyNPhKWG6gLda+R+PnC0RjRNAu0EHVy7ejhZkP8BYcG4R05rSaEQkH86Mqy3YMtXARV+0ReiMLUUSPNpLJWzSmbaApxQg/tnlYbVg6Cy4PtygdnGSQ6oqAld8kZ6pWTZeNjgL3cDOCXPZUGqDjO9iwumqDYiVyfHA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625936; c=relaxed/simple; bh=gzEph50CMKYWc/2RzHgjwSr/eSkelmxLwSNoIw/pV/E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lsp3q7VcAoU44qEc50UH3JTDlMWmDIhjOEwyKFUpQO0PPQG8+yyb0o830l5VgNAGr2IB8mJvihm6Ef/9kUzDC015yybRFiJCQT8uh2rfn2zouX9r9/JaXqK/fkaORUHGReHEQiYKMxaPEclp4Rf7T69ALOznF9PYAhp0PaKBUSQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=jAhTTqR7; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=XsYrHFoA; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="jAhTTqR7"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="XsYrHFoA" Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41]) by mailfhigh.stl.internal (Postfix) with ESMTP id C9C3B254020E; Wed, 26 Feb 2025 22:12:13 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-01.internal (MEProxy); Wed, 26 Feb 2025 22:12:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625933; x= 1740712333; bh=tlNpy+1s0z/XXtMrDxajZ6ojSkUYPqcxJ6nv+synffs=; b=j AhTTqR7z/IoQPzKDlQKS9Qu86ZWdhGzNDfVXb0THxSsxRK9s/1//9cfrXVwlUGE7 VuYMTLjzlkeGCmsxzQBg94E8EsXxtDrR4PZzZlVH/ibX+sXgswuwywx4UOuXNjYK PT82atID1Mx77nYUG20EYiFQapjCIJmNkRP5UU7FG02Yy2YqyxkazS/QCRTg3AG8 /vSDfI6rWh8RUqNJ0FEbIgb2Ju1De2GXGvN1Skqt0T658ZRhfs/EAlMnuaIAZPKY AkOdJgaduLhF8vCDwCqD1r1EKIqrgbdZdYgbvU4w5XcQcNgFn+O04JcUAOkMjt9Q WcipG5eKEqxNi6NPXFLtw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625933; x=1740712333; bh=t lNpy+1s0z/XXtMrDxajZ6ojSkUYPqcxJ6nv+synffs=; b=XsYrHFoADJoeUx0HL 6/sGNVuy5xLuYXYjRpLDujDdnm41DkE+i8WU2gheSZOJ4dyHC3RiDevuEE24fNnH NhDChRtLbeUezw9puOBYJ2P73ng/fsxz2X08AcOEumWkvSOIlJR9KmQToApi9bH8 tDrPlORSQYbniDDj+vfaAiuajxxTxKMrLog3Qy6l3bYmcpk/ZuCQNPxHDwAj5uo5 0irichrLBET2RWBBb+liaJSHpuKVIe9j+3efXrS3ugkRgFase2O2mZZzIXTWWGVz M/f6xwN3DN4wcK9JJsATlMqSVaHwV8CTWn9356McU2DIhYhx6es38Fi0TXAmKJHC WYkSw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dunecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:12:07 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 18/20] lib: rspdm: Support SPDM certificate validation Date: Thu, 27 Feb 2025 13:09:50 +1000 Message-ID: <20250227030952.2319050-19-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Signed-off-by: Alistair Francis --- lib/rspdm/lib.rs | 17 ++++++ lib/rspdm/state.rs | 95 ++++++++++++++++++++++++++++++++- rust/bindings/bindings_helper.h | 2 + 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index 1535e3a69518..b7ad3b8c659e 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -137,6 +137,17 @@ provisioned_slots &= !(1 << slot); } + let mut provisioned_slots = state.provisioned_slots; + while (provisioned_slots as usize) > 0 { + let slot = provisioned_slots.trailing_zeros() as u8; + + if let Err(e) = state.validate_cert_chain(slot) { + return e.to_errno() as c_int; + } + + provisioned_slots &= !(1 << slot); + } + 0 } @@ -145,6 +156,12 @@ /// @spdm_state: SPDM session state #[no_mangle] pub unsafe extern "C" fn spdm_destroy(state: &'static mut SpdmState) { + if let Some(leaf_key) = &mut state.leaf_key { + unsafe { + bindings::public_key_free(*leaf_key); + } + } + if let Some(desc) = &mut state.desc { unsafe { bindings::kfree(*desc as *mut _ as *mut c_void); diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index ae259623fe50..974d2ee8c0ce 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -12,7 +12,7 @@ use kernel::prelude::*; use kernel::{ bindings, - error::{code::EINVAL, to_result, Error}, + error::{code::EINVAL, from_err_ptr, to_result, Error}, str::CStr, validate::Untrusted, }; @@ -76,9 +76,10 @@ /// @slot: Certificate chain in each of the 8 slots. NULL pointer if a slot is /// not populated. Prefixed by the 4 + H header per SPDM 1.0.0 table 15. /// @slot_sz: Certificate chain size (in bytes). +/// @leaf_key: Public key portion of leaf certificate against which to check +/// responder's signatures. /// /// `authenticated`: Whether device was authenticated successfully. -#[expect(dead_code)] pub struct SpdmState { pub(crate) dev: *mut bindings::device, pub(crate) transport: bindings::spdm_transport, @@ -111,6 +112,7 @@ pub struct SpdmState { // Certificates pub(crate) slot: [Option>; SPDM_SLOTS], slot_sz: [usize; SPDM_SLOTS], + pub(crate) leaf_key: Option<*mut bindings::public_key>, } #[repr(C, packed)] @@ -153,6 +155,7 @@ pub(crate) fn new( authenticated: false, slot: [const { None }; SPDM_SLOTS], slot_sz: [0; SPDM_SLOTS], + leaf_key: None, } } @@ -745,4 +748,92 @@ pub(crate) fn get_certificate(&mut self, slot: u8) -> Result<(), Error> { Ok(()) } + + pub(crate) fn validate_cert_chain(&mut self, slot: u8) -> Result<(), Error> { + let cert_chain_buf = self.slot[slot as usize].as_ref().ok_or(ENOMEM)?; + let cert_chain_len = self.slot_sz[slot as usize]; + let header_len = 4 + self.hash_len; + + let mut offset = header_len; + let mut prev_cert: Option<*mut bindings::x509_certificate> = None; + + while offset < cert_chain_len { + let cert_len = unsafe { + bindings::x509_get_certificate_length( + &cert_chain_buf[offset..] as *const _ as *const u8, + cert_chain_len - offset, + ) + }; + + if cert_len < 0 { + pr_err!("Invalid certificate length\n"); + to_result(cert_len as i32)?; + } + + let _is_leaf_cert = if offset + cert_len as usize == cert_chain_len { + true + } else { + false + }; + + let cert_ptr = unsafe { + from_err_ptr(bindings::x509_cert_parse( + &cert_chain_buf[offset..] as *const _ as *const c_void, + cert_len as usize, + ))? + }; + let cert = unsafe { *cert_ptr }; + + if cert.unsupported_sig || cert.blacklisted { + to_result(-(bindings::EKEYREJECTED as i32))?; + } + + if let Some(prev) = prev_cert { + // Check against previous certificate + let rc = unsafe { bindings::public_key_verify_signature((*prev).pub_, cert.sig) }; + + if rc < 0 { + pr_err!("Signature validation error\n"); + to_result(rc)?; + } + } else { + // Check aginst root keyring + let key = unsafe { + from_err_ptr(bindings::find_asymmetric_key( + self.keyring, + (*cert.sig).auth_ids[0], + (*cert.sig).auth_ids[1], + (*cert.sig).auth_ids[2], + false, + ))? + }; + + let rc = unsafe { bindings::verify_signature(key, cert.sig) }; + unsafe { bindings::key_put(key) }; + + if rc < 0 { + pr_err!("Root signature validation error\n"); + to_result(rc)?; + } + } + + if let Some(prev) = prev_cert { + unsafe { bindings::x509_free_certificate(prev) }; + } + + prev_cert = Some(cert_ptr); + offset += cert_len as usize; + } + + if let Some(prev) = prev_cert { + if let Some(validate) = self.validate { + let rc = unsafe { validate(self.dev, slot, prev) }; + to_result(rc)?; + } + + self.leaf_key = unsafe { Some((*prev).pub_) }; + } + + Ok(()) + } } diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 5ba1191429f8..daeb599fb990 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include From patchwork Thu Feb 27 03:09:51 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993672 Received: from fhigh-b5-smtp.messagingengine.com (fhigh-b5-smtp.messagingengine.com [202.12.124.156]) (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 84A35187FEC; Thu, 27 Feb 2025 03:12:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.156 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625943; cv=none; b=RSvjR7csWxqE74ACErM6z2e6rnqX2T2wYVYMxfGTlzI+LDuRKdEqB/nHi0tiiha1nvEc6MvhiUUZrK2VSMbfGmGkdJVkUv3cFsv56RhlLYBW5dEFWJ/y65GrdXHarpqjNsyRaSih74E3GdEPT9BOYcVQfAef25D8tIBb8TmQiIA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625943; c=relaxed/simple; bh=d8dJ5M4zJTm+b/6IDp9srMSkKH4ua8cTtauEjhffqWo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X7xck4PiGe+Up5b6yl8jli5irpi1hmEhzBUBarK2JPyVEDdOIpcmhPYs8CD1bz5wlpCDaUDvXcjzcsL2QQklm++52H8rg+54fpiPRwk30It6dHj9vYpMAghkI1BdxN346MQsPKZ84DEvoGqm7fAW6PxWEuK4h0owEIeSd4kBwSI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=hD3Yp0uW; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=lPhz2HeY; arc=none smtp.client-ip=202.12.124.156 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="hD3Yp0uW"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="lPhz2HeY" Received: from phl-compute-03.internal (phl-compute-03.phl.internal [10.202.2.43]) by mailfhigh.stl.internal (Postfix) with ESMTP id 33832254020F; Wed, 26 Feb 2025 22:12:21 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Wed, 26 Feb 2025 22:12:21 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625941; x= 1740712341; bh=b4h8AeBhBbZ9HfizaA1Uykb1ePIl2dcXDnlikuYxKw8=; b=h D3Yp0uWUDUfv+HKRe3j023AGDLT/YqXanuODtRLqDVQKZ+xlaij9AHiAQ9OEXQQO b6vUos9ZrWuW8nR4iX+rd5WYulvkniKnE5yiPyoQVeOtusnkoxiordpUUpF76CHP rXM0/1gm3TKzCQf6Rd1COuvlAFK94rc1N7WTRTj+AW+m1G++2PWqVQRmXXXsUBiw WxeHx2xy/HUJ40mS1ckIcd1HWTGmgaB2IC2lZXDoGrt02l84tUVNUEwJyUI57XCO w6phYmPixe7FS6PlL9VFZcJ7GQMqkfqPQwa5yIxqZUsLJaaoHCfEkAFUcRF77Z0V mtyJQ1DR4e86zeWPnf10w== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625941; x=1740712341; bh=b 4h8AeBhBbZ9HfizaA1Uykb1ePIl2dcXDnlikuYxKw8=; b=lPhz2HeYMc43Mli2d 0LWyWuemDWKh3LJ0kLnHGvPfVkVADQt9dHN+m53xaYJ+/pbzogimAGgo08HPpfRG KgFWjsNpmygI4ERwbhKN1hjscnvb0us1OTp+oeOyusanQBFlr9QfokFGTWvCnaMc fjI8vAQG0dhCPp7Uw9Gw47apfZib44r1MY+RXc7xPIwy+UR50V35JhX2zcsSgJrg XeqovE8Yuf24S9sdJYMl12f2JrYDrJq8IHNooVUW9SHK41tFm79CuTy08pnMqPEf dhrfgAdxG7NnWDJsW/oLoylevNQjI3davhFri5ueSijCYS/8qsY8wPQ1A/dvT+HZ 1irbQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpeeitdefkeetledvleevveeu ueejffeugfeuvdetkeevjeejueetudeftefhgfehheenucevlhhushhtvghrufhiiigvpe dtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghirhesrghlihhsthgrihhr vdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepshhmthhpohhuthdprhgtph htthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthht oheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpth htoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthhopehlihhnuhigqdhptghi sehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsghhvghlghgrrghssehgoh hoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdrtggrmhgvrhhonheshhhu rgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqdhlihhnuhigsehvghgvrh drkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehlihhnuhigqdhfohhunhgu rghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvghnghesghhmrghilhdrtg homh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:12:14 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 19/20] rust: allow extracting the buffer from a CString Date: Thu, 27 Feb 2025 13:09:51 +1000 Message-ID: <20250227030952.2319050-20-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The kernel CString is a wrapper aroud a KVec. This patch allows retrieving the underlying buffer and consuming the CString. This allows users to create a CString from a string and then retrieve the underlying buffer. Signed-off-by: Alistair Francis --- rust/kernel/str.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 28e2201604d6..76862e91b81a 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -855,6 +855,11 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result { // exist in the buffer. Ok(Self { buf }) } + + /// Return the internal buffer while consuming the original [`CString`] + pub fn take_buffer(self) -> KVec { + self.buf + } } impl Deref for CString { From patchwork Thu Feb 27 03:09:52 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 13993673 Received: from fout-b5-smtp.messagingengine.com (fout-b5-smtp.messagingengine.com [202.12.124.148]) (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 D30F31AA1E4; Thu, 27 Feb 2025 03:12:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.12.124.148 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625951; cv=none; b=bFimsrGtStY/CJqTNFRbEgr09hW5ypG5dbJ4XLHqVMYAXiPmW9iPBAdClfO/4I3LF6z1947fFMVnGK7Iv/8N5NX9luwbE4hit7MZeoG8PKwzOCEOvQLF8w7087a7vbwqY+81O4zSSFi1CIosspSLmnNJOX5kMbgcBQqBxvzDK3M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740625951; c=relaxed/simple; bh=oLc6vRpYJ0xDVs2Dp2SxK42oRhdIET3pEOCkPPlQDTk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ocImuJMpYwdht4L6GbW13dJiqs5R/eWehlwKhl1NqHOHBbUIf2AUYUMkUPpGYsrZwgd05xqkF5jZd3jbuSVh1EtdJkQrj0OVOGLTUeGfT5gF6xBnWhSBvXSLLyX5cuehzchpMoCeuaVazBUcEFe4zVNTsgZdF1ynXHfOr42wodk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me; spf=pass smtp.mailfrom=alistair23.me; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b=HamN6V9y; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b=Iu21XGJ5; arc=none smtp.client-ip=202.12.124.148 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=alistair23.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alistair23.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=alistair23.me header.i=@alistair23.me header.b="HamN6V9y"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="Iu21XGJ5" Received: from phl-compute-06.internal (phl-compute-06.phl.internal [10.202.2.46]) by mailfout.stl.internal (Postfix) with ESMTP id 9F82411401BD; Wed, 26 Feb 2025 22:12:28 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-06.internal (MEProxy); Wed, 26 Feb 2025 22:12:29 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alistair23.me; h=cc:cc:content-transfer-encoding:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm1; t=1740625948; x= 1740712348; bh=gvplroEYlID/SuFvQTVuGaL+OgftQDgU+sH7ibNw/EY=; b=H amN6V9ykH3sBV6UobUMbew3hkf75Yw6PYVR0ys3kaNBYBUTqe5imt/gEaTSfJnDM oIEd24RF0wqzWagEX+E/2ZHvEOVnM7/GraGg2q2WEADiYkaPCcWZrlQCHwNQTBVi U8Et3NsljPvdAJQ5Cg8dak1N8DQkp22i+G0Oh+ufqDNLUrLneXKOzrh6z5Mu2lp7 jOTUU27pVVxMfkmOERra6j31XCI8gvufuINrgVvpWEu1LYJg5IEPlkqazerFaIvn xaFnmcSE9Bth0afhNtVXWlnW0MSjLJtZr+1/5zsbxdbc7HYDM9CH5YjyUXv2kbHw H0E7Q8wfiUIa0Akjxe6IQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1740625948; x=1740712348; bh=g vplroEYlID/SuFvQTVuGaL+OgftQDgU+sH7ibNw/EY=; b=Iu21XGJ5gtoE3EMn2 2pe/AJr/BA6qKaH3n1mUOPEB0/QOgmIPpxrbuDLH572NiB5KxYxGs27mh7ClqRZg WtDD7bbUFYOWG/QlCoG8D7hj9Vs052kSV6hZPhucnILkoxvHI5ILfGeekIsxXk6o xL2ldfRj0kL+3LDlPjOy/BajMdl1kHM5WEUUNRhEGQk0PF60yyQAUzEi+MffV4iI DsuzkvKa19ZDoFCPVgvBY2GEVtUpcloZhfYI49jDkhl9dseGJrFQrA6dVkNhhDh6 lNBYq4UYnSl8fk7yHD3Uwk2KW1GcYA4tyAtb8IQ1vd28BTFs3XtrKARMisQ2k2io q1m2g== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdekieefiecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecuogfuohhrthgvugftvg gtihhpvdculdegtddmnecujfgurhephffvvefufffkofgjfhgggfestdekredtredttden ucfhrhhomheptehlihhsthgrihhrucfhrhgrnhgtihhsuceorghlihhsthgrihhrsegrlh hishhtrghirhdvfedrmhgvqeenucggtffrrghtthgvrhhnpefhvedvvdefjeduffeujefh hfeigfelheelvdfgfeejueeuhfelieffleehleekudenucffohhmrghinhepsggrshgvpg grshihmhgpvghntgdrrghspdgsrghsvggphhgrshhhpggrlhhgpghnrghmvgdrrghspdht rhgrnhhstghrihhpthdrrghspdhophgrqhhuvggpuggrthgrpghlvghnrdhtohenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpegrlhhishhtrghi rhesrghlihhsthgrihhrvdefrdhmvgdpnhgspghrtghpthhtohepvddtpdhmohguvgepsh hmthhpohhuthdprhgtphhtthhopehlihhnuhigqdgtgihlsehvghgvrhdrkhgvrhhnvghl rdhorhhgpdhrtghpthhtoheplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvg hlrdhorhhgpdhrtghpthhtoheplhhukhgrshesfihunhhnvghrrdguvgdprhgtphhtthho pehlihhnuhigqdhptghisehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtohepsg hhvghlghgrrghssehgohhoghhlvgdrtghomhdprhgtphhtthhopehjohhnrghthhgrnhdr tggrmhgvrhhonheshhhurgifvghirdgtohhmpdhrtghpthhtoheprhhushhtqdhfohhrqd hlihhnuhigsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhrtghpthhtoheprghkphhmsehl ihhnuhigqdhfohhunhgurghtihhonhdrohhrghdprhgtphhtthhopegsohhquhhnrdhfvg hnghesghhmrghilhdrtghomh X-ME-Proxy: Feedback-ID: ifd214418:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 26 Feb 2025 22:12:22 -0500 (EST) From: Alistair Francis To: linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org, lukas@wunner.de, linux-pci@vger.kernel.org, bhelgaas@google.com, Jonathan.Cameron@huawei.com, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org Cc: boqun.feng@gmail.com, bjorn3_gh@protonmail.com, wilfred.mallawa@wdc.com, aliceryhl@google.com, ojeda@kernel.org, alistair23@gmail.com, a.hindborg@kernel.org, tmgross@umich.edu, gary@garyguo.net, alex.gaynor@gmail.com, benno.lossin@proton.me, Alistair Francis Subject: [RFC v2 20/20] lib: rspdm: Support SPDM challenge Date: Thu, 27 Feb 2025 13:09:52 +1000 Message-ID: <20250227030952.2319050-21-alistair@alistair23.me> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250227030952.2319050-1-alistair@alistair23.me> References: <20250227030952.2319050-1-alistair@alistair23.me> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Signed-off-by: Alistair Francis --- lib/rspdm/consts.rs | 6 + lib/rspdm/lib.rs | 8 +- lib/rspdm/state.rs | 212 ++++++++++++++++++++++++++++++-- lib/rspdm/validator.rs | 65 +++++++++- rust/bindings/bindings_helper.h | 1 + 5 files changed, 283 insertions(+), 9 deletions(-) diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs index ffaf36ec583b..af4e1a98dc5b 100644 --- a/lib/rspdm/consts.rs +++ b/lib/rspdm/consts.rs @@ -98,6 +98,8 @@ pub(crate) enum SpdmErrorCode { pub(crate) const SPDM_GET_CERTIFICATE: u8 = 0x82; +pub(crate) const SPDM_CHALLENGE: u8 = 0x83; + #[cfg(CONFIG_CRYPTO_RSA)] pub(crate) const SPDM_ASYM_RSA: u32 = SPDM_ASYM_RSASSA_2048 | SPDM_ASYM_RSASSA_3072 | SPDM_ASYM_RSASSA_4096; @@ -127,3 +129,7 @@ pub(crate) enum SpdmErrorCode { // pub(crate) const SPDM_MAX_REQ_ALG_STRUCT: usize = 4; pub(crate) const SPDM_OPAQUE_DATA_FMT_GENERAL: u8 = 1 << 1; + +pub(crate) const SPDM_PREFIX_SZ: usize = 64; +pub(crate) const SPDM_COMBINED_PREFIX_SZ: usize = 100; +pub(crate) const SPDM_MAX_OPAQUE_DATA: usize = 1024; diff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs index b7ad3b8c659e..c0e3e039c14f 100644 --- a/lib/rspdm/lib.rs +++ b/lib/rspdm/lib.rs @@ -137,17 +137,23 @@ provisioned_slots &= !(1 << slot); } + let mut verify = true; let mut provisioned_slots = state.provisioned_slots; while (provisioned_slots as usize) > 0 { let slot = provisioned_slots.trailing_zeros() as u8; if let Err(e) = state.validate_cert_chain(slot) { - return e.to_errno() as c_int; + pr_debug!("Certificate in slot {slot} failed to verify: {e:?}"); + verify = false; } provisioned_slots &= !(1 << slot); } + if let Err(e) = state.challenge(state.provisioned_slots.trailing_zeros() as u8, verify) { + return e.to_errno() as c_int; + } + 0 } diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index 974d2ee8c0ce..4629c12a1b81 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -14,23 +14,27 @@ bindings, error::{code::EINVAL, from_err_ptr, to_result, Error}, str::CStr, + str::CString, validate::Untrusted, }; use crate::consts::{ SpdmErrorCode, SPDM_ASYM_ALGOS, SPDM_ASYM_ECDSA_ECC_NIST_P256, SPDM_ASYM_ECDSA_ECC_NIST_P384, SPDM_ASYM_ECDSA_ECC_NIST_P521, SPDM_ASYM_RSASSA_2048, SPDM_ASYM_RSASSA_3072, - SPDM_ASYM_RSASSA_4096, SPDM_ERROR, SPDM_GET_VERSION_LEN, SPDM_HASH_ALGOS, SPDM_HASH_SHA_256, - SPDM_HASH_SHA_384, SPDM_HASH_SHA_512, SPDM_KEY_EX_CAP, SPDM_MAX_VER, SPDM_MEAS_CAP_MASK, - SPDM_MEAS_SPEC_DMTF, SPDM_MIN_DATA_TRANSFER_SIZE, SPDM_MIN_VER, SPDM_OPAQUE_DATA_FMT_GENERAL, + SPDM_ASYM_RSASSA_4096, SPDM_COMBINED_PREFIX_SZ, SPDM_ERROR, SPDM_GET_VERSION_LEN, + SPDM_HASH_ALGOS, SPDM_HASH_SHA_256, SPDM_HASH_SHA_384, SPDM_HASH_SHA_512, SPDM_KEY_EX_CAP, + SPDM_MAX_OPAQUE_DATA, SPDM_MAX_VER, SPDM_MEAS_CAP_MASK, SPDM_MEAS_SPEC_DMTF, + SPDM_MIN_DATA_TRANSFER_SIZE, SPDM_MIN_VER, SPDM_OPAQUE_DATA_FMT_GENERAL, SPDM_PREFIX_SZ, SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_SLOTS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12, }; use crate::validator::{ - GetCapabilitiesReq, GetCapabilitiesRsp, GetCertificateReq, GetCertificateRsp, GetDigestsReq, - GetDigestsRsp, GetVersionReq, GetVersionRsp, NegotiateAlgsReq, NegotiateAlgsRsp, RegAlg, - SpdmErrorRsp, SpdmHeader, + ChallengeReq, ChallengeRsp, GetCapabilitiesReq, GetCapabilitiesRsp, GetCertificateReq, + GetCertificateRsp, GetDigestsReq, GetDigestsRsp, GetVersionReq, GetVersionRsp, + NegotiateAlgsReq, NegotiateAlgsRsp, RegAlg, SpdmErrorRsp, SpdmHeader, }; +const SPDM_CONTEXT: &str = "responder-challenge_auth signing"; + /// The current SPDM session state for a device. Based on the /// C `struct spdm_state`. /// @@ -78,6 +82,12 @@ /// @slot_sz: Certificate chain size (in bytes). /// @leaf_key: Public key portion of leaf certificate against which to check /// responder's signatures. +/// @transcript: Concatenation of all SPDM messages exchanged during an +/// authentication or measurement sequence. Used to verify the signature, +/// as it is computed over the hashed transcript. +/// @next_nonce: Requester nonce to be used for the next authentication +/// sequence. Populated from user space through sysfs. +/// If user space does not provide a nonce, the kernel uses a random one. /// /// `authenticated`: Whether device was authenticated successfully. pub struct SpdmState { @@ -113,6 +123,10 @@ pub struct SpdmState { pub(crate) slot: [Option>; SPDM_SLOTS], slot_sz: [usize; SPDM_SLOTS], pub(crate) leaf_key: Option<*mut bindings::public_key>, + + transcript: KVec, + + next_nonce: Option<&'static mut [u8]>, } #[repr(C, packed)] @@ -156,6 +170,8 @@ pub(crate) fn new( slot: [const { None }; SPDM_SLOTS], slot_sz: [0; SPDM_SLOTS], leaf_key: None, + transcript: KVec::new(), + next_nonce: None, } } @@ -263,7 +279,7 @@ fn spdm_err(&self, rsp: &SpdmErrorRsp) -> Result<(), Error> { /// The data in `request_buf` is sent to the device and the response is /// stored in `response_buf`. pub(crate) fn spdm_exchange( - &self, + &mut self, request_buf: &mut [u8], response_buf: &mut [u8], ) -> Result { @@ -271,6 +287,8 @@ pub(crate) fn spdm_exchange( let request: &mut SpdmHeader = Untrusted::new_mut(request_buf).validate_mut()?; let response: &SpdmHeader = Untrusted::new_ref(response_buf).validate()?; + self.transcript.extend_from_slice(request_buf, GFP_KERNEL)?; + let transport_function = self.transport.ok_or(EINVAL)?; // SAFETY: `transport_function` is provided by the new(), we are // calling the function. @@ -337,6 +355,12 @@ pub(crate) fn get_version(&mut self) -> Result<(), Error> { unsafe { response_vec.set_len(rc as usize) }; let response: &mut GetVersionRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + let rsp_sz = core::mem::size_of::() + + 2 + + response.version_number_entry_count as usize * 2; + + self.transcript + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?; let mut foundver = false; for i in 0..response.version_number_entry_count { @@ -400,6 +424,9 @@ pub(crate) fn get_capabilities(&mut self) -> Result<(), Error> { let response: &mut GetCapabilitiesRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + self.transcript + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?; + self.rsp_caps = u32::from_le(response.flags); if (self.rsp_caps & SPDM_RSP_MIN_CAPS) != SPDM_RSP_MIN_CAPS { to_result(-(bindings::EPROTONOSUPPORT as i32))?; @@ -539,6 +566,9 @@ pub(crate) fn negotiate_algs(&mut self) -> Result<(), Error> { let response: &mut NegotiateAlgsRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + self.transcript + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?; + self.base_asym_alg = response.base_asym_sel; self.base_hash_alg = response.base_hash_sel; self.meas_hash_alg = response.measurement_hash_algo; @@ -598,6 +628,10 @@ pub(crate) fn get_digests(&mut self) -> Result<(), Error> { unsafe { response_vec.set_len(rc as usize) }; let response: &mut GetDigestsRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + let rsp_sz = core::mem::size_of::() + response.param2 as usize * self.hash_len; + + self.transcript + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?; if rc < (core::mem::size_of::() @@ -659,6 +693,10 @@ fn get_cert_exchange( unsafe { response_vec.set_len(rc as usize) }; let response: &mut GetCertificateRsp = Untrusted::new_mut(response_vec).validate_mut()?; + let rsp_sz = core::mem::size_of::() + 4 + response.portion_length as usize; + + self.transcript + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?; if rc < (core::mem::size_of::() + response.portion_length as usize) as i32 @@ -836,4 +874,164 @@ pub(crate) fn validate_cert_chain(&mut self, slot: u8) -> Result<(), Error> { Ok(()) } + + pub(crate) fn challenge_rsp_len(&mut self, nonce_len: usize, opaque_len: usize) -> usize { + let mut length = + core::mem::size_of::() + self.hash_len + nonce_len + opaque_len + 2; + + if self.version >= 0x13 { + length += 8; + } + + length + self.sig_len + } + + fn verify_signature(&mut self, response_vec: &mut [u8]) -> Result<(), Error> { + let sig_start = response_vec.len() - self.sig_len; + let mut sig = bindings::public_key_signature::default(); + let mut mhash: KVec = KVec::new(); + + sig.s = &mut response_vec[sig_start..] as *mut _ as *mut u8; + sig.s_size = self.sig_len as u32; + sig.encoding = self.base_asym_enc.as_ptr(); + sig.hash_algo = self.base_hash_alg_name.as_ptr(); + + let mut m: KVec = KVec::new(); + m.extend_with(SPDM_COMBINED_PREFIX_SZ + self.hash_len, 0, GFP_KERNEL)?; + + if let Some(desc) = &mut self.desc { + desc.tfm = self.shash; + + unsafe { + to_result(bindings::crypto_shash_digest( + *desc, + self.transcript.as_ptr(), + (self.transcript.len() - self.sig_len) as u32, + m[SPDM_COMBINED_PREFIX_SZ..].as_mut_ptr(), + ))?; + }; + } else { + to_result(-(bindings::EPROTO as i32))?; + } + + if self.version <= 0x11 { + sig.digest = m[SPDM_COMBINED_PREFIX_SZ..].as_mut_ptr(); + } else { + let major = self.version >> 4; + let minor = self.version & 0xF; + + let output = CString::try_from_fmt(fmt!("dmtf-spdm-v{major:x}.{minor:x}.*dmtf-spdm-v{major:x}.{minor:x}.*dmtf-spdm-v{major:x}.{minor:x}.*dmtf-spdm-v{major:x}.{minor:x}.*"))?; + let mut buf = output.take_buffer(); + let zero_pad_len = SPDM_COMBINED_PREFIX_SZ - SPDM_PREFIX_SZ - SPDM_CONTEXT.len() - 1; + + buf.extend_with(zero_pad_len, 0, GFP_KERNEL)?; + buf.extend_from_slice(SPDM_CONTEXT.as_bytes(), GFP_KERNEL)?; + + m[..SPDM_COMBINED_PREFIX_SZ].copy_from_slice(&buf); + + mhash.extend_with(self.hash_len, 0, GFP_KERNEL)?; + + if let Some(desc) = &mut self.desc { + desc.tfm = self.shash; + + unsafe { + to_result(bindings::crypto_shash_digest( + *desc, + m.as_ptr(), + m.len() as u32, + mhash.as_mut_ptr(), + ))?; + }; + } else { + to_result(-(bindings::EPROTO as i32))?; + } + + sig.digest = mhash.as_mut_ptr(); + } + + sig.digest_size = self.hash_len as u32; + + if let Some(leaf_key) = self.leaf_key { + unsafe { to_result(bindings::public_key_verify_signature(leaf_key, &sig)) } + } else { + to_result(-(bindings::EPROTO as i32)) + } + } + + pub(crate) fn challenge(&mut self, slot: u8, verify: bool) -> Result<(), Error> { + let mut request = ChallengeReq::default(); + request.version = self.version; + request.param1 = slot; + + let nonce_len = request.nonce.len(); + + if let Some(nonce) = &self.next_nonce { + request.nonce.copy_from_slice(&nonce); + self.next_nonce = None; + } else { + unsafe { + bindings::get_random_bytes(&mut request.nonce as *mut _ as *mut c_void, nonce_len) + }; + } + + let req_sz = if self.version <= 0x12 { + core::mem::size_of::() - 8 + } else { + core::mem::size_of::() + }; + + let rsp_sz = self.challenge_rsp_len(nonce_len, SPDM_MAX_OPAQUE_DATA); + + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) }; + + let mut response_vec: KVec = KVec::with_capacity(rsp_sz, GFP_KERNEL)?; + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice + let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) }; + + let rc = self.spdm_exchange(request_buf, response_buf)?; + + if rc < (core::mem::size_of::() as i32) { + pr_err!("Truncated challenge response\n"); + to_result(-(bindings::EIO as i32))?; + } + + // SAFETY: `rc` bytes where inserted to the raw pointer by spdm_exchange + unsafe { response_vec.set_len(rc as usize) }; + + let _response: &mut ChallengeRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?; + + let opaque_len_offset = core::mem::size_of::() + self.hash_len + nonce_len; + let opaque_len = u16::from_le_bytes( + response_vec[opaque_len_offset..(opaque_len_offset + 2)] + .try_into() + .unwrap_or([0, 0]), + ); + + let rsp_sz = self.challenge_rsp_len(nonce_len, opaque_len as usize); + + if rc < rsp_sz as i32 { + pr_err!("Truncated challenge response\n"); + to_result(-(bindings::EIO as i32))?; + } + + self.transcript + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?; + + if verify { + /* Verify signature at end of transcript against leaf key */ + match self.verify_signature(&mut response_vec[..rsp_sz]) { + Ok(()) => { + pr_info!("Authenticated with certificate slot {slot}"); + self.authenticated = true; + } + Err(e) => { + pr_err!("Cannot verify challenge_auth signature: {e:?}"); + self.authenticated = false; + } + }; + } + + Ok(()) + } } diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs index a8bc3378676f..f8a5337841f0 100644 --- a/lib/rspdm/validator.rs +++ b/lib/rspdm/validator.rs @@ -17,7 +17,7 @@ }; use crate::consts::{ - SPDM_ASYM_ALGOS, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_CERTIFICATE, + SPDM_ASYM_ALGOS, SPDM_CHALLENGE, SPDM_CTEXPONENT, SPDM_GET_CAPABILITIES, SPDM_GET_CERTIFICATE, SPDM_GET_DIGESTS, SPDM_GET_VERSION, SPDM_HASH_ALGOS, SPDM_MEAS_SPEC_DMTF, SPDM_NEGOTIATE_ALGS, SPDM_REQ_CAPS, }; @@ -424,3 +424,66 @@ fn validate(unvalidated: &mut Unvalidated>) -> Result Ok(rsp) } } + +#[repr(C, packed)] +pub(crate) struct ChallengeReq { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) nonce: [u8; 32], + pub(crate) context: [u8; 8], +} + +impl Default for ChallengeReq { + fn default() -> Self { + ChallengeReq { + version: 0, + code: SPDM_CHALLENGE, + param1: 0, + param2: 0, + nonce: [0; 32], + context: [0; 8], + } + } +} + +#[repr(C, packed)] +pub(crate) struct ChallengeRsp { + pub(crate) version: u8, + pub(crate) code: u8, + pub(crate) param1: u8, + pub(crate) param2: u8, + + pub(crate) cert_chain_hash: __IncompleteArrayField, + pub(crate) nonce: [u8; 32], + pub(crate) message_summary_hash: __IncompleteArrayField, + + pub(crate) opaque_data_len: u16, + pub(crate) opaque_data: __IncompleteArrayField, + + pub(crate) context: [u8; 8], + pub(crate) signature: __IncompleteArrayField, +} + +impl Validate<&mut Unvalidated>> for &mut ChallengeRsp { + type Err = Error; + + fn validate(unvalidated: &mut Unvalidated>) -> Result { + let raw = unvalidated.raw_mut(); + if raw.len() < mem::size_of::() { + return Err(EINVAL); + } + + let ptr = raw.as_mut_ptr(); + // CAST: `ChallengeRsp` only contains integers and has `repr(C)`. + let ptr = ptr.cast::(); + // SAFETY: `ptr` came from a reference and the cast above is valid. + let rsp: &mut ChallengeRsp = unsafe { &mut *ptr }; + + // rsp.opaque_data_len = rsp.opaque_data_len.to_le(); + + Ok(rsp) + } +} diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index daeb599fb990..16b8602c6d1a 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -7,6 +7,7 @@ */ #include +#include #include #include #include