From nobody Thu Dec 18 23:42:59 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1746541996; cv=none; d=zohomail.com; s=zohoarc; b=cYOeUuA7M0Im9UdzeCoRNmPZp4kiIlAm+wfxKi/+5ch3pMgGVlRsa6Pj8qIRGOSXqeMwIO1J/4FAW6C8P1OvBdNtr7RptbnQFmJIMuiGKJkNMQlOfcGYzfZMtucNoiYW3JlAAz2Ck+CXKy2B8jHEt250qS4FyldfVwbHwsrd+jg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746541996; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=9eYdqxJiuFt77CPqaijLabp59oslkZaSZ7TfPtEsR98=; b=d8dg20xgplRcZasdhZUvAfkpfVORLm9Jq7Gy3hUmvB8uyQRxqRdDidM0osiKO8/0/s9i9PNap4kHcOnwutWNb5BKuAeGpMce8618UBjOQ+ZjJZkNudRwlIpAlhBUeXeE2J5u2eGAfGIPIv7EvU+iMEqKpKyZV5vOqizK8F66S8s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 17465419960581.0885855041615287; Tue, 6 May 2025 07:33:16 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.977422.1364458 (Exim 4.92) (envelope-from ) id 1uCJM1-00024A-3S; Tue, 06 May 2025 14:33:05 +0000 Received: by outflank-mailman (output) from mailman id 977422.1364458; Tue, 06 May 2025 14:33:05 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCJM0-00023h-VT; Tue, 06 May 2025 14:33:04 +0000 Received: by outflank-mailman (input) for mailman id 977422; Tue, 06 May 2025 14:33:03 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCJLz-0000Q4-Qm for xen-devel@lists.xen.org; Tue, 06 May 2025 14:33:03 +0000 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [2a00:1450:4864:20::62a]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 03d7f82e-2a87-11f0-9ffb-bf95429c2676; Tue, 06 May 2025 16:33:02 +0200 (CEST) Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-ad1d1f57a01so267621066b.2 for ; Tue, 06 May 2025 07:33:02 -0700 (PDT) Received: from rossla-pc.eng.citrite.net ([185.25.67.249]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ad1894c0356sm711598966b.100.2025.05.06.07.33.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 May 2025 07:33:00 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 03d7f82e-2a87-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1746541981; x=1747146781; darn=lists.xen.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9eYdqxJiuFt77CPqaijLabp59oslkZaSZ7TfPtEsR98=; b=RG8Tko5AN79qhEwbcEXi2O/naV+30YqIqq//N68nl99Ti1IOE8+YYKc98K9sxzWRrg LKU36Zm7qnMwdJGlFt8xQ2LMtqlFqb/LG45MrpclchRLzg6D1HM8ChwjjIDXg9wpKCcV CTWPeEuZuJ40XFVBT0m8jrPON5layqLHCa6yA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746541981; x=1747146781; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9eYdqxJiuFt77CPqaijLabp59oslkZaSZ7TfPtEsR98=; b=Ag8QwmyOhfoSAh2Lud0PkZWbuVbIczKxDZPyEOtyr5T+wGFCQ9kleih6X9VrPfdAAd zPA8X2zAZ2N+GipUmTZRDpFtVCmORAb3qMt10hmR7phgFscnVoGel4zcUecdo7EPXfyu 0HYvjaV85t2xE4IiSqbYq5/y86QtqL36VEGKxfiTYNWCnw4xQmdNFU4AXvRHGdQybarq zpV63mT0MMPFQm9Ju71gWLUp3f93cV2a45k3Rf2YJsjKWf/6ARtrTq9Td6jFXLvRajtw NyaHbQEJTQPIv5ncpG7wWSDTzpT+WNm8mattaOlxfetFD4tA1glO/z1HQMaPr6smo96Q 7Q6A== X-Gm-Message-State: AOJu0Yw7qFYDyBwXXRjo65uARfx2DlCWDlkrDeAXWQYF7fS7N3ls1EpW LnLWGGzWR1uLGMtreFDlxcbPu6VkWqlTp5WGVmRDRqaqCZ5W6GTZLr53DgONA5sQOBgew9B7YPQ = X-Gm-Gg: ASbGncuP7mizN/bmggUVhSvy47SV/rDiExgTcUH7T1vRQBayYQ8KY13Cayz0RC/SA1A /l2mBml2aAIUkz2k1TaQSUy3e5BM8/va0Aj4TEkPIhefxY0fFfdvfao03Z3LG8zVnF8kAqOKa7L Hsf/fNtyTqCArFLl6pNS3N6BYkylInxXBS3qYfo2VaDlsjcTPvkizmAM+MeBjcsV9ihj0nW8yhG KWDwPhuUePR6WvpYTB7+5nYJc5jvXuFfdLVGSfeUwbmvlH7EHbuRxsIqkRDZy81+W0HpcSQ8bFX d1gOMlVxLq6VW3pCI1ksxqwR2ETXBcdvZclPRHWy/plz7G6QsteSEQf0ctGTcsS2 X-Google-Smtp-Source: AGHT+IEiXGDQDlvPzzGzGCTZWf6cD7XqhHvy9Fd20UQ8ONMR3GNj0HjnJ8ERzNht3teHeTivvJGHcA== X-Received: by 2002:a17:907:3d8c:b0:acb:4f4a:cbd0 with SMTP id a640c23a62f3a-ad17b5ad337mr1566316466b.14.1746541981299; Tue, 06 May 2025 07:33:01 -0700 (PDT) From: Ross Lagerwall To: Xen-devel , xen-devel@lists.xenproject.org Cc: Kevin Lampis , Andrew Cooper , Anthony PERARD , Michal Orzel , Jan Beulich , Julien Grall , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Stefano Stabellini , Ross Lagerwall Subject: [PATCH 3/4] livepatch: Embed public key in Xen Date: Tue, 6 May 2025 15:32:15 +0100 Message-ID: <20250506143218.1782603-4-ross.lagerwall@citrix.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250506143218.1782603-1-ross.lagerwall@citrix.com> References: <20250506143218.1782603-1-ross.lagerwall@citrix.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1746541997232019000 Content-Type: text/plain; charset="utf-8" From: Kevin Lampis Make it possible to embed a public key in Xen to be used when verifying live patch payloads. Inclusion of the public key is optional. To avoid needing to include a DER / X.509 parser in the hypervisor, the public key is unpacked at build time and included in a form that is convenient for the hypervisor to consume. This is different approach from that used by Linux which embeds the entire X.509 certificate and builds in a parser for it. A suitable key can be created using openssl: openssl req -x509 -newkey rsa:2048 -keyout priv.pem -out pub.pem \ -sha256 -days 3650 -nodes \ -subj "/C=3DXX/ST=3DStateName/L=3DCityName/O=3DCompanyName/OU=3DCompany= SectionName/CN=3DCommonNameOrHostname" openssl x509 -inform PEM -in pub.pem -outform PEM -pubkey -nocert -out cryp= to/signing_key.pem Signed-off-by: Kevin Lampis Signed-off-by: Ross Lagerwall --- xen/common/Kconfig | 18 ++++++++++++++++++ xen/common/Makefile | 2 +- xen/common/livepatch.c | 41 ++++++++++++++++++++++++++++++++++++++++ xen/crypto/Makefile | 14 +++++++++++++- xen/tools/extract-key.py | 37 ++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100755 xen/tools/extract-key.py diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 4bec78c6f267..e3e4fe2f3477 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -481,6 +481,24 @@ config LIVEPATCH =20 If unsure, say Y. =20 +config PAYLOAD_SIGNING + bool "Verify signed LivePatch payloads" + depends on LIVEPATCH + select CRYPTO + help + Verify signed LivePatch payloads using an RSA public key built + into the Xen hypervisor. Selecting this option requires a + public key in PEM format to be available for embedding during + the build. + +config PAYLOAD_SIG_KEY + string "File name of payload signing public key" + default "signing_key.pem" + depends on PAYLOAD_SIGNING + help + The file name of an RSA public key in PEM format to be used for + verifying signed LivePatch payloads. + config FAST_SYMBOL_LOOKUP bool "Fast symbol lookup (bigger binary)" default y diff --git a/xen/common/Makefile b/xen/common/Makefile index ece6548bb072..c75cbfa868a0 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_LIVEPATCH) +=3D livepatch.o livepatch_elf.o obj-$(CONFIG_LLC_COLORING) +=3D llc-coloring.o obj-$(CONFIG_VM_EVENT) +=3D mem_access.o obj-y +=3D memory.o -obj-y +=3D mpi.o +obj-$(CONFIG_PAYLOAD_SIGNING) +=3D mpi.o obj-y +=3D multicall.o obj-y +=3D notifier.o obj-$(CONFIG_NUMA) +=3D numa.o diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index be9b7e367553..947d05671b4f 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -73,6 +75,12 @@ static struct livepatch_work livepatch_work; static DEFINE_PER_CPU(bool, work_to_do); static DEFINE_PER_CPU(struct tasklet, livepatch_tasklet); =20 +#ifdef CONFIG_PAYLOAD_SIGNING +/* The public key contained with Xen used to verify payload signatures. */ +extern const uint8_t xen_livepatch_key_data[]; +static struct rsa_public_key builtin_payload_key; +#endif + static int get_name(const struct xen_livepatch_name *name, char *n) { if ( !name->size || name->size > XEN_LIVEPATCH_NAME_SIZE ) @@ -2287,6 +2295,34 @@ static void cf_check livepatch_printall(unsigned cha= r key) spin_unlock(&payload_lock); } =20 +#ifdef CONFIG_PAYLOAD_SIGNING +static int __init load_builtin_payload_key(void) +{ + const uint8_t *ptr; + uint32_t len; + + rsa_public_key_init(&builtin_payload_key); + + ptr =3D xen_livepatch_key_data; + + memcpy(&len, ptr, sizeof(len)); + ptr +=3D sizeof(len); + builtin_payload_key.n =3D mpi_read_raw_data(ptr, len); + ptr +=3D len; + + memcpy(&len, ptr, sizeof(len)); + ptr +=3D sizeof(len); + builtin_payload_key.e =3D mpi_read_raw_data(ptr, len); + + return rsa_public_key_prepare(&builtin_payload_key); +} +#else +static int __init load_builtin_payload_key(void) +{ + return 0; +} +#endif + static int cf_check cpu_callback( struct notifier_block *nfb, unsigned long action, void *hcpu) { @@ -2305,6 +2341,11 @@ static struct notifier_block cpu_nfb =3D { static int __init cf_check livepatch_init(void) { unsigned int cpu; + int err; + + err =3D load_builtin_payload_key(); + if (err) + return err; =20 for_each_online_cpu ( cpu ) { diff --git a/xen/crypto/Makefile b/xen/crypto/Makefile index d88374ddf221..e81302d7cd54 100644 --- a/xen/crypto/Makefile +++ b/xen/crypto/Makefile @@ -1,3 +1,15 @@ obj-y +=3D rijndael.o -obj-y +=3D rsa.o +obj-$(CONFIG_PAYLOAD_SIGNING) +=3D rsa.o obj-y +=3D vmac.o + +obj-$(CONFIG_PAYLOAD_SIGNING) +=3D builtin_payload_key.o + +ifeq ($(CONFIG_PAYLOAD_SIGNING),y) +key_path :=3D $(srctree)/crypto/$(patsubst "%",%,$(CONFIG_PAYLOAD_SIG_KEY)) +$(obj)/builtin_payload_key.bin: $(key_path) $(srctree)/tools/extract-key.py + $(srctree)/tools/extract-key.py < $< > $@.new + $(call move-if-changed,$@.new,$@) + +$(obj)/builtin_payload_key.S: $(srctree)/tools/binfile $(obj)/builtin_payl= oad_key.bin FORCE + $(call if_changed,binfile,$(obj)/builtin_payload_key.bin xen_livepatch_ke= y_data) +endif diff --git a/xen/tools/extract-key.py b/xen/tools/extract-key.py new file mode 100755 index 000000000000..2980264b757d --- /dev/null +++ b/xen/tools/extract-key.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: GPL-2.0 + +import binascii +import struct +import sys +import subprocess +import re + +# Decode a certificate into a format suitable for embedding in Xen. + +out =3D subprocess.check_output(['openssl', 'rsa', '-pubin', '-inform', 'P= EM', + '-noout', '-text'], stdin=3Dsys.stdin, + universal_newlines=3DTrue) +combined =3D '' +for line in out.split('\n'): + line =3D line.rstrip() + if line.startswith(' '): + combined +=3D line.strip().replace(':', '') + match =3D re.match(r'Exponent: .* \(0x(.*)\)', line) + if match: + e =3D match.group(1) + +n =3D combined.lstrip('0') +if len(n) % 2 =3D=3D 1: + n =3D '0' + n +n =3D binascii.unhexlify(n) +e =3D e.lstrip('0') +if len(e) % 2 =3D=3D 1: + e =3D '0' + e +e =3D binascii.unhexlify(e) + +sys.stdout.buffer.write(struct.pack('I', len(n))) +sys.stdout.buffer.write(n) +sys.stdout.buffer.write(struct.pack('I', len(e))) +sys.stdout.buffer.write(e) --=20 2.49.0