From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail05.groups.io (mail05.groups.io [45.79.224.7]) by spool.mail.gandi.net (Postfix) with ESMTPS id 460A8740038 for ; Mon, 22 Apr 2024 07:52:56 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=TeoPIVINqvOen061yh6Rtvtb3oE69EHbQ/t96In4/bM=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Language:Content-Type:Content-Transfer-Encoding; s=20240206; t=1713772374; v=1; b=DbunT/oHbCxeu2+bBaa9H8Y4l14+uL1dc3FQfKaKk2nmOVil5LpdGhOt89VbTH3BkNxJ0OYt zumNKj4ZgCNZQH6jZ5nmRwsx+vOKJOsdPFwoLpoRAm9D8IN13AMJlkDIp0I7Ni7Go9YNGZVLb9R MZOrnTMG8N5iJWOkBN5VZt7TvHUMn72a0OUFQPak59fcLGHOg7Zkj/ZP9IT1dw0livTi3/yuwrN GI/SB8Jv8PTi6XjoHLYQlW7qgPpbJ48nMBwnfGuNpXmOA7SjDRt8Broxbo1+t8vmXqKbLy/aIHT zA13k0D9oYzk4iHYWIRS/kteEb1pxN+HvUDTi5opvffdQ== X-Received: by 127.0.0.2 with SMTP id kfXqYY7687511xk2JNME0LPv; Mon, 22 Apr 2024 00:52:54 -0700 X-Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) by mx.groups.io with SMTP id smtpd.web10.13127.1713772373709610567 for ; Mon, 22 Apr 2024 00:52:53 -0700 X-CSE-ConnectionGUID: W08kHTUFQR+eLL0FtztO/g== X-CSE-MsgGUID: LiIRfQu9S4628vtfBprSTw== X-IronPort-AV: E=McAfee;i="6600,9927,11051"; a="19850207" X-IronPort-AV: E=Sophos;i="6.07,220,1708416000"; d="scan'208";a="19850207" X-Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2024 00:52:52 -0700 X-CSE-ConnectionGUID: UyFrot4rQbOCaCRv/1yS4Q== X-CSE-MsgGUID: tbcVniJ0Sya7F3o2bwvgfQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.07,220,1708416000"; d="scan'208";a="28605162" X-Received: from orsmsx602.amr.corp.intel.com ([10.22.229.15]) by fmviesa004.fm.intel.com with ESMTP/TLS/AES256-GCM-SHA384; 22 Apr 2024 00:52:52 -0700 X-Received: from orsmsx612.amr.corp.intel.com (10.22.229.25) by ORSMSX602.amr.corp.intel.com (10.22.229.15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Mon, 22 Apr 2024 00:52:51 -0700 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX612.amr.corp.intel.com (10.22.229.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Mon, 22 Apr 2024 00:52:51 -0700 X-Received: from ORSEDG602.ED.cps.intel.com (10.7.248.7) by orsmsx610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35 via Frontend Transport; Mon, 22 Apr 2024 00:52:51 -0700 X-Received: from NAM02-SN1-obe.outbound.protection.outlook.com (104.47.57.41) by edgegateway.intel.com (134.134.137.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 22 Apr 2024 00:52:50 -0700 X-Received: from SJ1PR11MB6227.namprd11.prod.outlook.com (2603:10b6:a03:45a::10) by SA1PR11MB5780.namprd11.prod.outlook.com (2603:10b6:806:233::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7519.19; Mon, 22 Apr 2024 07:52:47 +0000 X-Received: from SJ1PR11MB6227.namprd11.prod.outlook.com ([fe80::301:5dbd:207b:5578]) by SJ1PR11MB6227.namprd11.prod.outlook.com ([fe80::301:5dbd:207b:5578%4]) with mapi id 15.20.7519.018; Mon, 22 Apr 2024 07:52:47 +0000 From: "Li, Yi" To: "Hou, Wenxing" , "devel@edk2.groups.io" CC: "Yao, Jiewen" Subject: Re: [edk2-devel] [PATCH 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtls Thread-Topic: [PATCH 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtls Thread-Index: AQHaj9LuCjmwjs7YjESWcdNoaLdfYLFz8leg Date: Mon, 22 Apr 2024 07:52:47 +0000 Message-ID: References: <20240416075118.4799-1-wenxing.hou@intel.com> <20240416075118.4799-6-wenxing.hou@intel.com> In-Reply-To: <20240416075118.4799-6-wenxing.hou@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: SJ1PR11MB6227:EE_|SA1PR11MB5780:EE_ x-ms-office365-filtering-correlation-id: 0994e9b3-1060-4dbb-e44b-08dc62a133a5 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: =?us-ascii?Q?dOeb1st9jmCj4hpXEwztvKfehfyzHqlNXDnv/XQNSiQzjxKTXIbGfhoq+Dn1?= =?us-ascii?Q?BbFX+OHE7CjExcurbOs7syxz2KaY8skrjluDmnt9e3QFlc+vqkSESnqpxIZn?= =?us-ascii?Q?Lsckt00s6tXFSXLYOd4/otEoLYOxDuWvs4r9tPFiHViTebvri8RXbEzEWLPP?= =?us-ascii?Q?2ve9+fvqd+cRtSx4Y0bUgeUSgzUw8Cj4hYEw7BO8MEmgjcq3ZFCaek5AjZI1?= =?us-ascii?Q?Dr993+aq20zkQ7RG4NUuB+qENJFHsqjRpkW0ZGxmHtcg8tvX/9vbw84Oa+Am?= =?us-ascii?Q?EAIiV1Hqkxsaomjv9IjxGrqFVzP4JBneQ1OOjTZO50z5qqhqtaU8T88oayCI?= =?us-ascii?Q?tTon/pN/K+edZGzSeQ7ZowrERY6PCwMed7zGSWURBny7wz1iMMX/roiReGX6?= =?us-ascii?Q?5oXBwCW70gPdpvMnsOK68y2HS8eTWu6bgerhKmpw8t0Rg5Qj6cl/egrCLomO?= =?us-ascii?Q?PbJG3c+1tGsk9HAIOyOFVQqpRMFtSjGszHFHKGcMLtLjvDQd4E1KN/hGBlJ6?= =?us-ascii?Q?jgEQ2MxJ0iDVmoJqivvmPMpGlCfYe6maqtwFhiqpS74yo9+zyZszdsC7EfLD?= =?us-ascii?Q?apvPBxeXLox547q1DWoA/jXnHuUv4Xr4UVGLV6gnZdLMQZAOOP1CSw07XCbp?= =?us-ascii?Q?GWJjSBZs3xP/zWz8adICCqgFYdjlaK+v8mxgnXeHmuJyM5HmS6HR9aL6Mc93?= =?us-ascii?Q?/iDZviEl9omL1PfzDxTX/Fqo8fFgi+pDQkD1YemE1Uf0oPO1SUJR/LVKeHeR?= =?us-ascii?Q?yrqTgBXNyWi5JpaJkzE6tnDOAJEBo2SASbTwfgSpBv0MuO4/VNZJcSJVSBGv?= =?us-ascii?Q?9wgyMhfKry6nU2B0uIPtKCpd/NLzYyv2L8XPXKRudeSFbuKW5PkdLBKq4DC5?= =?us-ascii?Q?BROr/k95dMWGrr7USt/BuXovT/adtSs7kmKpli1GXbopT9QAYCX6+LyckARR?= =?us-ascii?Q?QRiJ8OBuOACM3QllFZNM+BVMwXir00w80vTmyhGk/OYRK596c71KXkD6mv/B?= =?us-ascii?Q?rXvaOqIJZo8Kd2y0K+vgRqqZ9sap70gllxV+G7t3hd6hv7tBBeOFXAVwOnvv?= =?us-ascii?Q?tF9y7yIEZ7jq2TxTUVC/R+/cDAIGRaMbo5FrJdKpHtQh4Lw9VhPQ2vXrgZnP?= =?us-ascii?Q?+Y2CD9CVPI9oRykiGqiNA7EhsyRh2hnbRKwVUQFxwZ5a79pb5wQfRdVCQhjB?= =?us-ascii?Q?t+yQzEbdjg8wVjEhenJ2ozOyKSB4nB+YsdfZfM5n6IdR98AfI8FU1xErd+Ip?= =?us-ascii?Q?2Dr2+S3mvURLxGUdk0iONO2rgBSV1kiz5nPugY3WJ/JAvgIDsMe9kl6lGcZi?= =?us-ascii?Q?hh8=3D?= x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?tVEaPIve1kWdQSSz/HgApmixxdoiG79GHB415DdVSVL4pvuvqKd8ntyiRHtY?= =?us-ascii?Q?CmRO1/Iq3bVeCtSCdImKwljdGrzYhUObcV2nlvxz3z9p1ZSNsLCyXZthytu5?= =?us-ascii?Q?3Fe9pvzYYzAhB14xbfRqyCnnjyCvJFuA+PQiIAk7bZoucND8VbsUU0CGxfqg?= =?us-ascii?Q?KCBQb/zQ8KnlCBYqWlsHsUVgMaUlH1TyogBxwaE2Q5Grwt07nNxroXwK9xhi?= =?us-ascii?Q?zrWd60vzQGQ32mTTewCGnP4be5vd2LQHl7jLmkCHNsUfXzH5ZnD+eFqEWdqa?= =?us-ascii?Q?l1UV4BG2db0w8nWZnUBpPqfxKMWNUQneeBR8DUcJ25iVhGkqiNIuNzenAAc1?= =?us-ascii?Q?iQe5AZmV+kvjJDzxfh7OW91AuX1A/uct5yNtYcDGpgvBMmVa7LUt1KzyExza?= =?us-ascii?Q?BO1r7EMqkyvbUy5lw93sPjkw91KKXRs8rUXlIiimazLzf+ieO33NYxgpG7m0?= =?us-ascii?Q?mH5AnW8FDGsxQXin1jGTEOjaGP4LWoP558qF5MOlV/yZNVFD3eIYnLhRdlLA?= =?us-ascii?Q?+m+8Ohd7nhzuOXxYnT1/UsnijYUSnK00BDNwHV0KwChOopVX96fxH2e/zuKx?= =?us-ascii?Q?syGDZmTbMEipoph69gFFW3d1PSjpA+XK1xuML8vPe1Z3eCVLQYUOr9rJIuYA?= =?us-ascii?Q?61e3J8P1VbVcLE+YGJPV+MITtSD1AlGy1XIcQzqIGMdtd4MMIBCsWBCZxi4P?= =?us-ascii?Q?sciUjPLdhXPLUw4E0EkPB51BkrAxTw3VpikXqAOTQFN/j+EgVTwrYsTTqCjT?= =?us-ascii?Q?bRoSBthu0XtTeY6TBWDUMfjsCxsuLvdnZ73MnAkcS2WkZjaq7Oc3UOEl/Qzw?= =?us-ascii?Q?reAAsJbr8EgsfrHJgGtmFLdfquGyJdJ9Ki95+Nc9yPbYLpYy56Ab1qcrFrsM?= =?us-ascii?Q?oVWnCurGmBQBCJJUCdsmL1wf9UuwAE1MYavrmQ70Skg8OhctJVKomYJ3kcSi?= =?us-ascii?Q?NspsjcrbG/0y7tvDH5qPV9/9pOdWYnEppgm9zV4/34nHLVURVO3gK7w7mQBY?= =?us-ascii?Q?crCca08MOseAezTU3NyrKyGdepjVFQR+Ktj/lxYxPRXmXEPLx8uMcjR0/f9N?= =?us-ascii?Q?wgWmTtaTEGo2TpRzw8BZp16UPyeCh30DtrR0ba1qb+KfU+pTxxVaE5QBpetb?= =?us-ascii?Q?frB/1CdoTU3b6mEa1NfqR6w+AUZxtIZLAdEuGKGk7oBwOb4xyAhS9iHkxtT6?= =?us-ascii?Q?byVWJEba6CiZik6pTaqIBJUPK2ayRuX+ysjJqsNg1RfrhNj6pVJQFu6ZE9ne?= =?us-ascii?Q?sAlmhcSSwCe6R/G5Q8ZhWJA2Sy01YCX0S4QT0Y+1G36LX9K+0yqLe32Pyqel?= =?us-ascii?Q?YO+GQrCHmH7uqRQP4pgKYwFTGjkgyU8+VnLo1tIrC07AcJZ/1DnbkHy8yxX1?= =?us-ascii?Q?AueGZR/tw+02bKg3jXsuJ9IMESCNlnN+E8P35ZL5zHtYjQ25Hmm4IDTTI83n?= =?us-ascii?Q?0mC0aGJs6u/E9yt+YrMVLdLLlsViuHOAk3o9bauhb7sDDqbPYyGWbQ/JBBfi?= =?us-ascii?Q?a66gk2E0szeI7m/XFgu3K71JCnsDKo/a+enpxQOwkgvdVjcwv/40e+wRiduB?= =?us-ascii?Q?PDlHVQi3f0N04OpOayQ=3D?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: SJ1PR11MB6227.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0994e9b3-1060-4dbb-e44b-08dc62a133a5 X-MS-Exchange-CrossTenant-originalarrivaltime: 22 Apr 2024 07:52:47.5024 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: Klqp1wxHwQvcBTcMp7NXw4ZZLEki0B2YrXiLj8AWRFLOEgOayOtMvEXQO4Vyme6gSNry7zjJMCnE+Ro077Fp3g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA1PR11MB5780 X-OriginatorOrg: intel.com Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Mon, 22 Apr 2024 00:52:53 -0700 Resent-From: yi1.li@intel.com Reply-To: devel@edk2.groups.io,yi1.li@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: MK18RLrBKuwgCNpGxhWjmduvx7686176AA= Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b="DbunT/oH"; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 45.79.224.7 as permitted sender) smtp.mailfrom=bounce@groups.io The pools used to store cert chain are not released properly, which will le= ad to memory leak problems Please ensure MbedtlsPkcs7SignedData.Certificates are handled correctly whe= n: 1. error occurred in Pkcs7GetSigner/SignedData 2. Pkcs7Verify finished. Regards, Yi -----Original Message----- From: Hou, Wenxing =20 Sent: Tuesday, April 16, 2024 3:51 PM To: devel@edk2.groups.io Cc: Yao, Jiewen ; Li, Yi1 Subject: [PATCH 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtl= s REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4177 Because the current Mbedlts pkcs7 library doesn't support authenticatedAttributes: Mbed-TLS/mbedtls@bb82ab7 and only support 0 or 1 certificates in Signed data: tianocore/edk2-staging@9c5b26b The patch implement Pkcs7 by low Mbedtls Api. And the implementation has pass unit_tes and integration test. Cc: Jiewen Yao Cc: Yi Li Signed-off-by: Wenxing Hou --- .../BaseCryptLibMbedTls/InternalCryptLib.h | 33 + .../Pk/CryptPkcs7Internal.h | 20 +- .../BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c | 615 ++++++++ .../Pk/CryptPkcs7VerifyBase.c | 113 ++ .../Pk/CryptPkcs7VerifyCommon.c | 1315 +++++++++++++++++ .../Pk/CryptPkcs7VerifyEku.c | 689 +++++++++ 6 files changed, 2773 insertions(+), 12 deletions(-) create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign= .c create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Veri= fyBase.c create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Veri= fyCommon.c create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Veri= fyEku.c diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h b/Cry= ptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h index e2c7e42ecb..1b9742c166 100644 --- a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h @@ -38,4 +38,37 @@ MbedtlsRand ( UINT8 *output, UINTN len ); + +/** + Check input P7Data is a wrapped ContentInfo structure or not. If not con= struct + a new structure to wrap P7Data. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do = basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, othe= rwise + return FALSE. + @param[out] WrapData If return status of this function is TRUE: + 1) when WrapFlag is TRUE, pointer to P7Data. + 2) when WrapFlag is FALSE, pointer to a new Con= tentInfo + structure. It's caller's responsibility to free= this + buffer. + @param[out] WrapDataSize Length of ContentInfo structure in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE The operation is failed due to lack of resource= s. + +**/ +BOOLEAN +WrapPkcs7Data ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT BOOLEAN *WrapFlag, + OUT UINT8 **WrapData, + OUT UINTN *WrapDataSize + ); + #endif diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h = b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h index 207f493cbb..d4bdb0abf7 100644 --- a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h @@ -4,7 +4,7 @@ =20 RFC 2315 - PKCS #7: Cryptographic Message Syntax Version 1.5 =20 -Copyright (c) 2023, Intel Corporation. All rights reserved.
+Copyright (c) 2023-2024, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent =20 **/ @@ -31,10 +31,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x= 05" #define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x= 06" =20 -typedef mbedtls_asn1_buf MBEDTLSPKCS7BUF; -typedef mbedtls_asn1_named_data MBEDTLSPKCS7NAME; -typedef mbedtls_asn1_sequence MBEDTLSPKCS7SEQUENCE; - /// /// PKCS7 SignerInfo type /// https://tools.ietf.org/html/rfc2315#section-9.2 @@ -48,8 +44,8 @@ typedef struct MbedtlsPkcs7SignerInfo { mbedtls_x509_buf SigAlgIdentifier; mbedtls_x509_buf AuthAttr; mbedtls_x509_buf Sig; - struct MBEDTLSPKCS7SIGNERINFO *Next; -} MBEDTLSPKCS7SIGNERINFO; + struct MbedtlsPkcs7SignerInfo *Next; +} MbedtlsPkcs7SignerInfo; =20 /// /// PKCS7 signed data attached data format @@ -57,7 +53,7 @@ typedef struct MbedtlsPkcs7SignerInfo { typedef struct MbedtlsPkcs7Data { mbedtls_asn1_buf Oid; mbedtls_asn1_buf Data; -} MBEDTLSPKCS7DATA; +} MbedtlsPkcs7Data; =20 /// /// Signed Data @@ -66,18 +62,18 @@ typedef struct MbedtlsPkcs7Data { typedef struct MbedtlsPkcs7SignedData { INT32 Version; mbedtls_asn1_buf DigestAlgorithms; - struct MBEDTLSPKCS7DATA ContentInfo; + struct MbedtlsPkcs7Data ContentInfo; mbedtls_x509_crt Certificates; mbedtls_x509_crl Crls; struct MbedtlsPkcs7SignerInfo SignerInfos; -} MBEDTLSPKCS7SIGNEDDATA; +} MbedtlsPkcs7SignedData; =20 /// /// PKCS7 struct, only support SignedData /// typedef struct MbedtlsPkcs7 { mbedtls_asn1_buf ContentTypeOid; - struct MBEDTLSPKCS7SIGNEDDATA SignedData; -} MBEDTLSPKCS7; + struct MbedtlsPkcs7SignedData SignedData; +} MbedtlsPkcs7; =20 #endif diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c b/Cr= yptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c new file mode 100644 index 0000000000..e4d2d7a2a8 --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c @@ -0,0 +1,615 @@ +/** @file + PKCS#7 SignedData Sign Wrapper and PKCS#7 SignedData Verification Wrappe= r + Implementation over mbedtls. + + RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites + FIPS 186-4 - Digital Signature Standard (DSS) + +Copyright (c) 2024, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CryptPkcs7Internal.h" +#include + +/// +/// Enough to store any signature generated by PKCS7 +/// +#define MAX_SIGNATURE_SIZE 1024 + +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 MbedtlsOidDigestAlgSha256[] =3D MBEDT= LS_OID_DIGEST_ALG_SHA256; +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 MbedtlsOidPkcs1Rsa[] =3D MBEDT= LS_OID_PKCS1_RSA; + +/** + Write DigestAlgorithmIdentifier. + + @param[in, out] P The reference to the current position point= er. + @param[in] Start The start of the buffer, for bounds-checkin= g. + @param[in] DigestType Digest Type + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteDigestAlgorithm ( + UINT8 **P, + UINT8 *Start, + mbedtls_md_type_t DigestType + ) +{ + UINT8 *OidPtr; + UINTN OidLen; + INT32 Ret; + + Ret =3D mbedtls_oid_get_oid_by_md (DigestType, (CONST CHAR8 **)&OidPtr, = &OidLen); + if (Ret =3D=3D 0) { + return mbedtls_asn1_write_oid (P, (CONST UINT8 *)Start, (CONST CHAR8 *= )OidPtr, OidLen); + } + + return 0; +} + +/** + DigestAlgorithmIdentifiers ::=3D + SET OF DigestAlgorithmIdentifier. + + @param[in, out] P The reference to the current position point= er. + @param[in] Start The start of the buffer, for bounds-checkin= g. + @param[in] DigestTypes Digest Type array. + @param[in] Count The index for Digest Type. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteDigestAlgorithmSet ( + UINT8 **P, + UINT8 *Start, + mbedtls_md_type_t *DigestTypes, + INTN Count + ) +{ + INTN Idx; + INT32 Len; + INT32 ret; + + Len =3D 0; + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_null (P, Start)); + + for (Idx =3D 0; Idx < Count; Idx++) { + MBEDTLS_ASN1_CHK_ADD ( + Len, + MbedTlsPkcs7WriteDigestAlgorithm (P, Start, DigestTypes[Idx]) + ); + } + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, (UINTN)Len)= ); + + MBEDTLS_ASN1_CHK_ADD ( + Len, + mbedtls_asn1_write_tag ( + P, + Start, + (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) + ) + ); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, (UINTN)Len)= ); + + MBEDTLS_ASN1_CHK_ADD ( + Len, + mbedtls_asn1_write_tag ( + P, + Start, + (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) + ) + ); + + return Len; +} + +/** + ContentInfo ::=3D SEQUENCE { + contentType ContentType, + content + [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }. + + @param[in, out] P The reference to the current position point= er. + @param[in] Start The start of the buffer, for bounds-checkin= g. + @param[in] Content ContentInfo. + @param[in] ContentLen Size of ContentInfo. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteContentInfo ( + UINT8 **P, + UINT8 *Start, + UINT8 *Content, + INTN ContentLen + ) +{ + INT32 ret; + INT32 Len; + + Len =3D 0; + if (Content !=3D NULL) { + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (P, Start, = Content, ContentLen)); + } + + MBEDTLS_ASN1_CHK_ADD ( + Len, + mbedtls_asn1_write_oid ( + P, + Start, + MBEDTLS_OID_PKCS7_DATA, + sizeof (MBEDTLS_OID_PKCS7_DATA) - 1 + ) + ); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return Len; +} + +/** + certificates :: SET OF ExtendedCertificateOrCertificate, + ExtendedCertificateOrCertificate ::=3D CHOICE { + certificate Certificate -- x509, + extendedCertificate[0] IMPLICIT ExtendedCertificate }. + + @param[in, out] P The reference to the current position point= er. + @param[in] Start The start of the buffer, for bounds-checkin= g. + @param[in] Cert Certificate. + @param[in] OtherCerts Ohter Certificate. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteCertificates ( + UINT8 **P, + UINT8 *Start, + mbedtls_x509_crt *Cert, + mbedtls_x509_crt *OtherCerts + ) +{ + INT32 ret; + INT32 Len; + mbedtls_x509_crt *TmpCert; + + Len =3D 0; + + /// Write OtherCerts + TmpCert =3D OtherCerts; + while (TmpCert !=3D NULL) { + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (P, Start, Tm= pCert->raw.p, TmpCert->raw.len)); + TmpCert =3D TmpCert->next; + } + + /// Write Cert + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (P, Start, Cert= ->raw.p, Cert->raw.len)); + + /// Write NextContext + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)); + return Len; +} + +/** + write Pkcs7 Int. + + @param[in, out] P The reference to the current position poin= ter. + @param[in] Start The start of the buffer, for bounds-checki= ng. + @param[in] SerialRaw SerialRaw. + @param[in] SerialRawLen Size of SerialRaw. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteInt ( + UINT8 **P, + UINT8 *Start, + UINT8 *SerialRaw, + INTN SerialRawLen + ) +{ + INT32 ret; + UINT8 *Ptr; + INT32 Len; + + Len =3D 0; + Ptr =3D SerialRaw + SerialRawLen; + while (Ptr > SerialRaw) { + *--(*P) =3D *--Ptr; + Len++; + } + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_INTEGER)); + + return Len; +} + +/** + write Pkcs7 Issuer And SerialNumber. + + @param[in, out] P The reference to the current position poin= ter. + @param[in] Start The start of the buffer, for bounds-checki= ng. + @param[in] Serial Serial. + @param[in] SerialLen Size of Serial. + @param[in] IssuerRaw IssuerRawLen. + @param[in] IssuerRawLen Size of IssuerRawLen. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteIssuerAndSerialNumber ( + UINT8 **P, + UINT8 *Start, + UINT8 *Serial, + INTN SerialLen, + UINT8 *IssuerRaw, + INTN IssuerRawLen + ) +{ + INT32 ret; + INT32 Len; + + Len =3D 0; + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteInt (P, Start, Serial, Seria= lLen)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (P, Start, Issu= erRaw, IssuerRawLen)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return Len; +} + +/** + SignerInfo ::=3D SEQUENCE { + version Version; + issuerAndSerialNumber IssuerAndSerialNumber, + digestAlgorithm DigestAlgorithmIdentifier, + authenticatedAttributes + [0] IMPLICIT Attributes OPTIONAL, + digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + encryptedDigest EncryptedDigest, + unauthenticatedAttributes + [1] IMPLICIT Attributes OPTIONAL. + + @param[in, out] P The reference to the current position poin= ter. + @param[in] Start The start of the buffer, for bounds-checki= ng. + @param[in] SignerInfo SignerInfo. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteSignerInfo ( + UINT8 **P, + UINT8 *Start, + MbedtlsPkcs7SignerInfo *SignerInfo + ) +{ + INT32 ret; + INT32 Len; + + Len =3D 0; + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (P, Start, Si= gnerInfo->Sig.p, SignerInfo->Sig.len)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (P, S= tart, (CONST CHAR8 *)SignerInfo->SigAlgIdentifier.p, SignerInfo->SigAlgIden= tifier.len, 0)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (P, S= tart, (CONST CHAR8 *)SignerInfo->AlgIdentifier.p, SignerInfo->AlgIdentifier= .len, 0)); + + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteIssuerAndSerialNumber (P, St= art, SignerInfo->Serial.p, SignerInfo->Serial.len, SignerInfo->IssuerRaw.p,= SignerInfo->IssuerRaw.len)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (P, Start, SignerInfo-= >Version)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return Len; +} + +/** + write Pkcs7 Signers Info Set. + + @param[in, out] P The reference to the current position poin= ter. + @param[in] Start The start of the buffer, for bounds-checki= ng. + @param[in] SignersSet SignerInfo Set. + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteSignersInfoSet ( + UINT8 **P, + UINT8 *Start, + MbedtlsPkcs7SignerInfo *SignersSet + ) +{ + MbedtlsPkcs7SignerInfo *SignerInfo; + INT32 ret; + INT32 Len; + + SignerInfo =3D SignersSet; + Len =3D 0; + + while (SignerInfo !=3D NULL) { + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignerInfo (P, Start, Sign= erInfo)); + // move to next + SignerInfo =3D SignerInfo->Next; + } + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_CONSTRUCTED | MBEDTLS_ASN1_SET)); + + return Len; +} + +/** + Signed Data Type + SignedData ::=3D SEQUENCE { + version Version, + digestAlgorithms DigestAlgorithmIdentifiers, + contentInfo ContentInfo, + certificates + [0] IMPLICIT ExtendedCertificatesAndCertificates + OPTIONAL, + crls + [1] IMPLICIT CertificateRevocationLists OPTIONAL, + signerInfos SignerInfos } + + DigestAlgorithmIdentifiers ::=3D + SET OF DigestAlgorithmIdentifier + + SignerInfos ::=3D SET OF SignerInfo. + + @param[in, out] P The reference to the current position poin= ter. + @param[in] Start The start of the buffer, for bounds-checki= ng. + @param[in] Pkcs7 MbedtlsPkcs7 + + @retval number The number of bytes written to p on success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure. +**/ +STATIC +INT32 +MbedTlsPkcs7WriteDer ( + UINT8 **P, + UINT8 *Start, + MbedtlsPkcs7 *Pkcs7 + ) +{ + INT32 ret; + INT32 Len; + mbedtls_md_type_t DigestAlg[1]; + + DigestAlg[0] =3D MBEDTLS_MD_SHA256; + Len =3D 0; + + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignersInfoSet (P, Start, &(= Pkcs7->SignedData.SignerInfos))); + + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteCertificates (P, Start, &(Pk= cs7->SignedData.Certificates), Pkcs7->SignedData.Certificates.next)); + + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteContentInfo (P, Start, NULL,= 0)); + + MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteDigestAlgorithmSet (P, Start= , DigestAlg, 1)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (P, Start, Pkcs7->Sign= edData.Version)); + + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len)); + MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN= 1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return Len; +} + +/** + Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Mess= age + Syntax Standard, version 1.5". This interface is only intended to be use= d for + application to perform PKCS#7 functionality validation. + + If this interface is not supported, then return FALSE. + + @param[in] PrivateKey Pointer to the PEM-formatted private key da= ta for + data signing. + @param[in] PrivateKeySize Size of the PEM private key data in bytes. + @param[in] KeyPassword NULL-terminated passphrase used for encrypt= ed PEM + key data. + @param[in] InData Pointer to the content to be signed. + @param[in] InDataSize Size of InData in bytes. + @param[in] SignCert Pointer to signer's DER-encoded certificate= to sign with. + @param[in] OtherCerts Pointer to an optional additional set of ce= rtificates to + include in the PKCS#7 signedData (e.g. any = intermediate + CAs in the chain). + @param[out] SignedData Pointer to output PKCS#7 signedData. It's c= aller's + responsibility to free the buffer with Free= Pool(). + @param[out] SignedDataSize Size of SignedData in bytes. + + @retval TRUE PKCS#7 data signing succeeded. + @retval FALSE PKCS#7 data signing failed. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7Sign ( + IN CONST UINT8 *PrivateKey, + IN UINTN PrivateKeySize, + IN CONST UINT8 *KeyPassword, + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *SignCert, + IN UINT8 *OtherCerts OPTIONAL, + OUT UINT8 **SignedData, + OUT UINTN *SignedDataSize + ) +{ + BOOLEAN Status; + INT32 Ret; + mbedtls_pk_context Pkey; + UINT8 HashValue[SHA256_DIGEST_SIZE]; + UINT8 Signature[MAX_SIGNATURE_SIZE]; + UINTN SignatureLen; + UINT8 *NewPrivateKey; + mbedtls_x509_crt *Crt; + + MbedtlsPkcs7 Pkcs7; + MbedtlsPkcs7SignerInfo SignerInfo; + UINT8 *Buffer; + INTN BufferSize; + UINT8 *P; + INT32 Len; + + BufferSize =3D 4096; + + SignatureLen =3D MAX_SIGNATURE_SIZE; + Crt =3D (mbedtls_x509_crt *)SignCert; + + NewPrivateKey =3D NULL; + if (PrivateKey[PrivateKeySize - 1] !=3D 0) { + NewPrivateKey =3D AllocateZeroPool (PrivateKeySize + 1); + if (NewPrivateKey =3D=3D NULL) { + return FALSE; + } + + CopyMem (NewPrivateKey, PrivateKey, PrivateKeySize); + NewPrivateKey[PrivateKeySize] =3D 0; + PrivateKeySize++; + } else { + NewPrivateKey =3D AllocateZeroPool (PrivateKeySize); + if (NewPrivateKey =3D=3D NULL) { + return FALSE; + } + + CopyMem (NewPrivateKey, PrivateKey, PrivateKeySize); + } + + mbedtls_pk_init (&Pkey); + Ret =3D mbedtls_pk_parse_key ( + &Pkey, + NewPrivateKey, + PrivateKeySize, + KeyPassword, + KeyPassword =3D=3D NULL ? 0 : AsciiStrLen ((CONST CHAR8 *)KeyPas= sword), + NULL, + NULL + ); + if (Ret !=3D 0) { + Status =3D FALSE; + goto Cleanup; + } + + /// Calculate InData Digest + ZeroMem (HashValue, SHA256_DIGEST_SIZE); + Status =3D Sha256HashAll (InData, InDataSize, HashValue); + if (!Status) { + goto Cleanup; + } + + /// Pk Sign + ZeroMem (Signature, MAX_SIGNATURE_SIZE); + Ret =3D mbedtls_pk_sign ( + &Pkey, + MBEDTLS_MD_SHA256, + HashValue, + SHA256_DIGEST_SIZE, + Signature, + MAX_SIGNATURE_SIZE, + &SignatureLen, + MbedtlsRand, + NULL + ); + if (Ret !=3D 0) { + Status =3D FALSE; + goto Cleanup; + } + + ZeroMem (&Pkcs7, sizeof (MbedtlsPkcs7)); + Pkcs7.SignedData.Version =3D 1; + + Crt->next =3D (mbedtls_x509_crt *)OtherCerts; + Pkcs7.SignedData.Certificates =3D *Crt; + + SignerInfo.Next =3D NULL; + SignerInfo.Sig.p =3D Signature; + SignerInfo.Sig.len =3D SignatureLen; + SignerInfo.Version =3D 1; + SignerInfo.AlgIdentifier.p =3D MbedtlsOidDigestAlgSha256; + SignerInfo.AlgIdentifier.len =3D sizeof (MBEDTLS_OID_DIGEST_ALG_SHA256) = - 1; + if (mbedtls_pk_get_type (&Pkey) =3D=3D MBEDTLS_PK_RSA) { + SignerInfo.SigAlgIdentifier.p =3D MbedtlsOidPkcs1Rsa; + SignerInfo.SigAlgIdentifier.len =3D sizeof (MBEDTLS_OID_PKCS1_RSA) - 1= ; + } else { + mbedtls_oid_get_oid_by_sig_alg (MBEDTLS_PK_ECDSA, MBEDTLS_MD_SHA256, (= CONST CHAR8 **)&SignerInfo.SigAlgIdentifier.p, &SignerInfo.SigAlgIdentifier= .len); + } + + SignerInfo.Serial =3D ((mbedtls_x509_crt *)SignCert)->serial; + SignerInfo.IssuerRaw =3D ((mbedtls_x509_crt *)SignCert)->issuer_= raw; + Pkcs7.SignedData.SignerInfos =3D SignerInfo; + + Buffer =3D AllocateZeroPool (BufferSize); + if (Buffer =3D=3D NULL) { + Status =3D FALSE; + goto Cleanup; + } + + P =3D Buffer + BufferSize; + Len =3D MbedTlsPkcs7WriteDer (&P, Buffer, &Pkcs7); + + /// Enlarge buffer if buffer is too small + while (Len < 0 && Len =3D=3D MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) { + BufferSize =3D BufferSize * 2; + P =3D Buffer + BufferSize; + FreePool (Buffer); + Buffer =3D AllocateZeroPool (BufferSize); + if (Buffer =3D=3D NULL) { + Status =3D FALSE; + goto Cleanup; + } + + P =3D Buffer + BufferSize; + Len =3D MbedTlsPkcs7WriteDer (&P, Buffer, &Pkcs7); + } + + if (Len <=3D 0) { + Status =3D FALSE; + goto Cleanup; + } + + *SignedData =3D AllocateZeroPool (Len); + *SignedDataSize =3D Len; + CopyMem (*SignedData, P, Len); + Status =3D TRUE; + +Cleanup: + if (&Pkey !=3D NULL) { + mbedtls_pk_free (&Pkey); + } + + if (NewPrivateKey !=3D NULL) { + FreePool (NewPrivateKey); + } + + if (Buffer !=3D NULL) { + FreePool (Buffer); + } + + return Status; +} diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.= c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c new file mode 100644 index 0000000000..6b62ee2618 --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c @@ -0,0 +1,113 @@ +/** @file + Non-runtime specific implementation of PKCS#7 SignedData Verification Wr= apper. + +Copyright (c) 2024, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + Extracts the attached content from a PKCS#7 signed data if existed. The = input signed + data could be wrapped in a ContentInfo structure. + + If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Leng= th overflow, + then return FALSE. If the P7Data is not correctly formatted, then return= FALSE. + + Caution: This function may receive untrusted input. So this function wil= l do + basic check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 signed data to process. + @param[in] P7Length Length of the PKCS#7 signed data in bytes. + @param[out] Content Pointer to the extracted content from the PKCS= #7 signedData. + It's caller's responsibility to free the buffe= r with FreePool(). + @param[out] ContentSize The size of the extracted content in bytes. + + @retval TRUE The P7Data was correctly formatted for process= ing. + @retval FALSE The P7Data was not correctly formatted for pro= cessing. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetAttachedContent ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT VOID **Content, + OUT UINTN *ContentSize + ) +{ + BOOLEAN Status; + UINT8 *SignedData; + UINTN SignedDataSize; + BOOLEAN Wrapped; + INTN Ret; + mbedtls_pkcs7 Pkcs7; + mbedtls_pkcs7_data *MbedtlsContent; + + mbedtls_pkcs7_init (&Pkcs7); + + // + // Check input parameter. + // + if ((P7Data =3D=3D NULL) || (P7Length > INT_MAX) || (Content =3D=3D NULL= ) || (ContentSize =3D=3D NULL)) { + return FALSE; + } + + *Content =3D NULL; + SignedData =3D NULL; + + Status =3D WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &Sign= edDataSize); + if (!Status || (SignedDataSize > INT_MAX)) { + goto _Exit; + } + + Status =3D FALSE; + + Ret =3D mbedtls_pkcs7_parse_der (&Pkcs7, SignedData, (INT32)SignedDataSi= ze); + + // + // The type of Pkcs7 must be signedData + // + if (Ret !=3D MBEDTLS_PKCS7_SIGNED_DATA) { + goto _Exit; + } + + // + // Check for detached or attached content + // + MbedtlsContent =3D &(Pkcs7.signed_data.content); + + if (MbedtlsContent =3D=3D NULL) { + // + // No Content supplied for PKCS7 detached signedData + // + *Content =3D NULL; + *ContentSize =3D 0; + } else { + // + // Retrieve the attached content in PKCS7 signedData + // + if ((MbedtlsContent->data.len > 0) && (MbedtlsContent->data.p !=3D NUL= L)) { + *ContentSize =3D MbedtlsContent->data.len; + *Content =3D AllocateZeroPool (*ContentSize); + if (*Content =3D=3D NULL) { + *ContentSize =3D 0; + goto _Exit; + } + + CopyMem (*Content, MbedtlsContent->data.p, *ContentSize); + } + } + + Status =3D TRUE; + +_Exit: + // + // Release Resources + // + mbedtls_pkcs7_free (&Pkcs7); + + return Status; +} diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommo= n.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c new file mode 100644 index 0000000000..f5ca4c528a --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c @@ -0,0 +1,1315 @@ +/** @file + PKCS#7 SignedData Sign Wrapper and PKCS#7 SignedData Verification Wrappe= r + Implementation over mbedtls. + + RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites + FIPS 186-4 - Digital Signature Standard (DSS) + +Copyright (c) 2024, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CryptPkcs7Internal.h" +#include + +/* Profile for backward compatibility. Allows RSA 1024, unlike the default + profile. */ +STATIC mbedtls_x509_crt_profile gCompatProfile =3D +{ + /* Hashes from SHA-256 and above. Note that this selection + * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */ + + #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES + MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA1) | + #endif + MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA256) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA384) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA512), + 0xFFFFFFF, /* Any PK alg */ + + /* Curves at or above 128-bit security level. Note that this selection + * should be aligned with ssl_preset_default_curves in ssl_tls.c. */ + MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP256R1) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP384R1) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP521R1) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP256R1) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP384R1) | + MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP512R1) | + 0, + 1024, +}; + +/** + Init MbedtlsPkcs7. + + @param[in] Pkcs7 MbedtlsPkcs7. +**/ +STATIC +VOID +MbedTlsPkcs7Init ( + MbedtlsPkcs7 *Pkcs7 + ) +{ + ZeroMem (Pkcs7, sizeof (MbedtlsPkcs7)); +} + +/** + Get Pkcs7 Next Content Len. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] Len MbedtlsPkcs7 Content Len. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedTlsPkcs7GetNextContentLen ( + UINT8 **P, + UINT8 *End, + UINTN *Len + ) +{ + INT32 Ret; + + Ret =3D mbedtls_asn1_get_tag (P, End, Len, MBEDTLS_ASN1_CONSTRUCTED | MB= EDTLS_ASN1_CONTEXT_SPECIFIC); + return Ret; +} + +/** + Get Pkcs7 Version.. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] Ver MbedtlsPkcs7 Version. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedTlsPkcs7GetVersion ( + UINT8 **P, + UINT8 *End, + INT32 *Ver + ) +{ + INT32 Ret; + + Ret =3D mbedtls_asn1_get_int (P, End, Ver); + return Ret; +} + +/** + ContentInfo ::=3D SEQUENCE { + contentType ContentType, + content + [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] Pkcs7 MbedtlsPkcs7. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +Pkcs7GetContentInfoType ( + UINT8 **P, + UINT8 *End, + mbedtls_asn1_buf *Pkcs7 + ) +{ + UINTN Len; + int Ret; + + Len =3D 0; + Ret =3D mbedtls_asn1_get_tag ( + P, + End, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + ); + + if (Ret =3D=3D 0) { + Ret =3D mbedtls_asn1_get_tag (P, End, &Len, MBEDTLS_ASN1_OID); + } + + if (Ret =3D=3D 0) { + Pkcs7->tag =3D MBEDTLS_ASN1_OID; + Pkcs7->len =3D Len; + Pkcs7->p =3D *P; + } + + return Ret; +} + +/** + DigestAlgorithmIdentifier ::=3D AlgorithmIdentifier. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] Alg MbedtlsPkcs7 AlgorithmIdentifier. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedTlsPkcs7GetDigestAlgorithm ( + UINT8 **P, + UINT8 *End, + mbedtls_x509_buf *Alg + ) +{ + INT32 Ret; + + Ret =3D mbedtls_asn1_get_alg_null (P, End, Alg); + return Ret; +} + +/** + DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] Alg MbedtlsPkcs7 AlgorithmIdentifier. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedTlsPkcs7GetDigestAlgorithmSet ( + UINT8 **P, + UINT8 *End, + mbedtls_x509_buf *Alg + ) +{ + UINTN Len; + INT32 Ret; + + Len =3D 0; + Ret =3D mbedtls_asn1_get_tag ( + P, + End, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET + ); + + if (Ret =3D=3D 0) { + End =3D *P + Len; + // assume only one digest algorithm + Ret =3D mbedtls_asn1_get_alg_null (P, End, Alg); + } + + return Ret; +} + +/** + certificates :: SET OF ExtendedCertificateOrCertificate, + ExtendedCertificateOrCertificate ::=3D CHOICE { + certificate Certificate -- x509, + extendedCertificate[0] IMPLICIT ExtendedCertificate }. + + @param[in] P The start of the buffer. + @param[in] Plen The buffer len. + @param[out] Certs mbedtls_x509_crt cert. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedTlsPkcs7GetCertificates ( + UINT8 **P, + INTN Plen, + mbedtls_x509_crt *Certs + ) +{ + INT32 Ret; + + Ret =3D mbedtls_x509_crt_parse (Certs, *P, Plen); + return Ret; +} + +/** + EncryptedDigest ::=3D OCTET STRING. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] Signature Signature. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +Pkcs7GetSignature ( + UINT8 **P, + UINT8 *End, + mbedtls_asn1_buf *Signature + ) +{ + INT32 Ret; + UINTN Len; + + Len =3D 0; + Ret =3D mbedtls_asn1_get_tag (P, End, &Len, MBEDTLS_ASN1_OCTET_STRING); + if (Ret =3D=3D 0) { + Signature->tag =3D MBEDTLS_ASN1_OCTET_STRING; + Signature->len =3D Len; + Signature->p =3D *P; + } + + return Ret; +} + +/** + SignerInfo ::=3D SEQUENCE { + version Version; + issuerAndSerialNumber IssuerAndSerialNumber, + digestAlgorithm DigestAlgorithmIdentifier, + authenticatedAttributes + [0] IMPLICIT Attributes OPTIONAL, + digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + encryptedDigest EncryptedDigest, + unauthenticatedAttributes + [1] IMPLICIT Attributes OPTIONAL. + + @param[in] P The start of the buffer. + @param[in] End The end of the buffer. + @param[out] SignersSet MbedtlsPkcs7SignerInfo. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedTlsPkcs7GetSignersInfoSet ( + UINT8 **P, + UINT8 *End, + MbedtlsPkcs7SignerInfo *SignersSet + ) +{ + UINT8 *EndSet; + INT32 Ret; + UINTN Len; + UINT8 *TempP; + + Len =3D 0; + + Ret =3D mbedtls_asn1_get_tag ( + P, + End, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET + ); + + if (Ret =3D=3D 0) { + EndSet =3D *P + Len; + + Ret =3D mbedtls_asn1_get_tag ( + P, + EndSet, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + ); + } + + if (Ret =3D=3D 0) { + Ret =3D mbedtls_asn1_get_int (P, EndSet, &SignersSet->Version); + } + + if (Ret =3D=3D 0) { + Ret =3D mbedtls_asn1_get_tag ( + P, + EndSet, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + ); + } + + if (Ret =3D=3D 0) { + SignersSet->IssuerRaw.p =3D *P; + Ret =3D mbedtls_asn1_get_tag ( + P, + EndSet, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SE= QUENCE + ); + } + + if (Ret =3D=3D 0) { + Ret =3D mbedtls_x509_get_name (P, *P + Len, &SignersSet->Issuer); + } + + if (Ret =3D=3D 0) { + SignersSet->IssuerRaw.len =3D *P - SignersSet->IssuerRaw.p; + + Ret =3D mbedtls_x509_get_serial (P, EndSet, &SignersSet->Serial); + } + + if (Ret =3D=3D 0) { + Ret =3D MbedTlsPkcs7GetDigestAlgorithm (P, EndSet, &SignersSet->AlgIde= ntifier); + } + + // OPTIONAL AuthenticatedAttributes + if (Ret =3D=3D 0) { + TempP =3D *P; + if (mbedtls_asn1_get_tag (&TempP, EndSet, &Len, MBEDTLS_ASN1_CONSTRUCT= ED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) =3D=3D 0) { + SignersSet->AuthAttr.len =3D Len + (TempP - *P); + SignersSet->AuthAttr.p =3D *P; + *P =3D TempP + Len; + } else { + SignersSet->AuthAttr.p =3D NULL; + } + } + + if (Ret =3D=3D 0) { + Ret =3D MbedTlsPkcs7GetDigestAlgorithm (P, EndSet, &SignersSet->SigAlg= Identifier); + } + + if (Ret =3D=3D 0) { + Ret =3D Pkcs7GetSignature (P, End, &SignersSet->Sig); + } + + if (Ret =3D=3D 0) { + SignersSet->Next =3D NULL; + } + + return Ret; +} + +/** + SignedData ::=3D SEQUENCE { + version Version, + digestAlgorithms DigestAlgorithmIdentifiers, + contentInfo ContentInfo, + certificates + [0] IMPLICIT ExtendedCertificatesAndCertificates + OPTIONAL, + crls + [0] IMPLICIT CertificateRevocationLists OPTIONAL, + signerInfos SignerInfos }. + + @param[in] Buffer The start of the buffer. + @param[in] BufferLen The len the buffer. + @param[out] SignedData MbedtlsPkcs7SignedData. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +Pkcs7GetSignedData ( + UINT8 *Buffer, + INTN BufferLen, + MbedtlsPkcs7SignedData *SignedData + ) +{ + UINT8 *P; + UINT8 *End; + UINTN Len; + INT32 Ret; + UINT8 *CertP; + UINTN CertLen; + UINT8 *OldCertP; + UINTN TotalCertLen; + mbedtls_x509_crt *MoreCert; + UINT8 CertNum; + mbedtls_x509_crt *LastCert; + + Len =3D 0; + P =3D Buffer; + End =3D Buffer + BufferLen; + MoreCert =3D NULL; + + Ret =3D mbedtls_asn1_get_tag ( + &P, + End, + &Len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + ); + + if (Ret =3D=3D 0) { + // version + Ret =3D MbedTlsPkcs7GetVersion (&P, End, &SignedData->Version); + } + + if ((Ret =3D=3D 0) && (SignedData->Version !=3D 1)) { + Ret =3D -1; + } + + if (Ret =3D=3D 0) { + // digest algorithm + Ret =3D MbedTlsPkcs7GetDigestAlgorithmSet ( + &P, + End, + &SignedData->DigestAlgorithms + ); + } + + if (Ret =3D=3D 0) { + if ( + #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES + ((SignedData->DigestAlgorithms.len =3D=3D sizeof (MBEDTLS_OID_DIGE= ST_ALG_SHA1) - 1) && + (CompareMem ( + SignedData->DigestAlgorithms.p, + MBEDTLS_OID_DIGEST_ALG_SHA1, + SignedData->DigestAlgorithms.len + ) =3D=3D 0)) || + #endif + ((SignedData->DigestAlgorithms.len =3D=3D sizeof (MBEDTLS_OID_DIGE= ST_ALG_SHA256) - 1) && + (CompareMem ( + SignedData->DigestAlgorithms.p, + MBEDTLS_OID_DIGEST_ALG_SHA256, + SignedData->DigestAlgorithms.len + ) =3D=3D 0)) || + ((SignedData->DigestAlgorithms.len =3D=3D sizeof (MBEDTLS_OID_DIGE= ST_ALG_SHA384) - 1) && + (CompareMem ( + SignedData->DigestAlgorithms.p, + MBEDTLS_OID_DIGEST_ALG_SHA384, + SignedData->DigestAlgorithms.len + ) =3D=3D 0)) || + ((SignedData->DigestAlgorithms.len =3D=3D sizeof (MBEDTLS_OID_DIGE= ST_ALG_SHA512) - 1) && + (CompareMem ( + SignedData->DigestAlgorithms.p, + MBEDTLS_OID_DIGEST_ALG_SHA512, + SignedData->DigestAlgorithms.len + ) =3D=3D 0))) + { + Ret =3D 0; + } else { + Ret =3D -1; + } + } + + if (Ret =3D=3D 0) { + Ret =3D Pkcs7GetContentInfoType (&P, End, &SignedData->ContentInfo.Oid= ); + } + + if (Ret =3D=3D 0) { + // move to next + P =3D P + SignedData->ContentInfo.Oid.len; + Ret =3D MbedTlsPkcs7GetNextContentLen (&P, End, &Len); + CertP =3D P + Len; + + // move to actual cert, if there are more [0] + if (MbedTlsPkcs7GetNextContentLen (&CertP, End, &CertLen) =3D=3D 0) { + Len =3D CertLen; + P =3D CertP; + } + } + + // certificates: may have many certs + CertP =3D P; + + TotalCertLen =3D 0; + + MoreCert =3D &SignedData->Certificates; + CertNum =3D 0; + + while (TotalCertLen < Len) { + OldCertP =3D CertP; + + Ret =3D mbedtls_asn1_get_tag (&CertP, End, &CertLen, MBEDTLS_ASN1_CONS= TRUCTED | MBEDTLS_ASN1_SEQUENCE); + if (Ret !=3D 0) { + goto End; + } + + // cert total len + CertLen =3D CertLen + (CertP - OldCertP); + + // move to next cert + CertP =3D OldCertP + CertLen; + + // change TotalCertLen + TotalCertLen +=3D CertLen; + + mbedtls_x509_crt_init (MoreCert); + Ret =3D MbedTlsPkcs7GetCertificates (&OldCertP, CertLen, MoreCert); + if (Ret !=3D 0) { + goto End; + } + + CertNum++; + MoreCert->next =3D AllocateZeroPool (sizeof (mbedtls_x509_crt)); + MoreCert =3D MoreCert->next; + } + + if (TotalCertLen !=3D Len) { + Ret =3D -1; + goto End; + } + + LastCert =3D &(SignedData->Certificates); + + while (CertNum--) { + if (CertNum =3D=3D 0) { + LastCert->next =3D NULL; + break; + } else { + LastCert =3D LastCert->next; + } + } + + // signers info + if (Ret =3D=3D 0) { + P =3D P + Len; + Ret =3D MbedTlsPkcs7GetSignersInfoSet (&P, End, &SignedData->SignerInf= os); + } + +End: + if (MoreCert !=3D NULL) { + FreePool (MoreCert); + MoreCert =3D NULL; + } + + return Ret; +} + +/** + Parse MbedtlsPkcs7 to Der format. + @param[in] Buffer The start of the buffer. + @param[in] BufferLen The len the buffer. + @param[out] Pkcs7 MbedtlsPkcs7. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedtlsPkcs7ParseDer ( + CONST UINT8 *Buffer, + INTN BufferLen, + MbedtlsPkcs7 *Pkcs7 + ) +{ + UINT8 *P; + UINT8 *End; + UINTN Len; + INT32 Ret; + + if (Pkcs7 =3D=3D NULL) { + return -1; + } + + Len =3D 0; + P =3D (UINT8 *)Buffer; + End =3D P + BufferLen; + + Ret =3D Pkcs7GetContentInfoType (&P, End, &Pkcs7->ContentTypeOid); + if (Ret !=3D 0) { + goto out; + } + + if ((CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_DATA, Pkcs7-= >ContentTypeOid.len) =3D=3D 0) || (CompareMem (Pkcs7->ContentTypeOid.p, MBE= DTLS_OID_PKCS7_ENCRYPTED_DATA, Pkcs7->ContentTypeOid.len) =3D=3D 0) || (Com= pareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_ENVELOPED_DATA, Pkcs7->= ContentTypeOid.len) =3D=3D 0) || (CompareMem (Pkcs7->ContentTypeOid.p, MBED= TLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, Pkcs7->ContentTypeOid.len) =3D=3D = 0) || (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_DIGESTED_DATA= , Pkcs7->ContentTypeOid.len) =3D=3D 0) || (CompareMem (Pkcs7->ContentTypeOi= d.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, Pkcs7->ContentTypeOid.len) =3D=3D 0)= ) { + // Invalid PKCS7 data type; + Ret =3D -1; + goto out; + } + + if (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_SIGNED_DATA, = Pkcs7->ContentTypeOid.len) !=3D 0) { + // Invalid PKCS7 data type; + Ret =3D -1; + goto out; + } + + // Content type is SignedData + P =3D P + Pkcs7->ContentTypeOid.len; + + Ret =3D MbedTlsPkcs7GetNextContentLen (&P, End, &Len); + if (Ret !=3D 0) { + goto out; + } + + Ret =3D Pkcs7GetSignedData (P, Len, &Pkcs7->SignedData); + if (Ret !=3D 0) { + goto out; + } + +out: + return Ret; +} + +/** + MbedtlsPkcs7 verify MbedtlsPkcs7SignerInfo. + @param[in] SignerInfo MbedtlsPkcs7 SignerInfo. + @param[in] Cert cert. + @param[in] Data Pointer for data. + @param[in] DataLen The len the buffer. + + @retval 0 Success. + @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on f= ailure. +**/ +STATIC +INT32 +MbedtlsPkcs7SignedDataVerifySigners ( + MbedtlsPkcs7SignerInfo *SignerInfo, + mbedtls_x509_crt *Cert, + CONST UINT8 *Data, + INTN DataLen + ) +{ + INT32 Ret; + UINT8 Hash[MBEDTLS_MD_MAX_SIZE]; + mbedtls_pk_context Pk; + CONST mbedtls_md_info_t *MdInfo; + INTN HashLen; + UINT8 TempAuthAttr; + + Pk =3D Cert->pk; + ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE); + + // all the hash algo + #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES + MdInfo =3D mbedtls_md_info_from_type (MBEDTLS_MD_SHA1); + HashLen =3D mbedtls_md_get_size (MdInfo); + mbedtls_md (MdInfo, Data, DataLen, Hash); + if (SignerInfo->AuthAttr.p !=3D NULL) { + TempAuthAttr =3D *(SignerInfo->AuthAttr.p); + *(SignerInfo->AuthAttr.p) =3D MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_= SET; + mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, = Hash); + // Restore content + *(SignerInfo->AuthAttr.p) =3D TempAuthAttr; + } + + Ret =3D mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA1, Hash, HashLen, SignerIn= fo->Sig.p, SignerInfo->Sig.len); + + if (Ret =3D=3D 0) { + return Ret; + } + + #endif + + MdInfo =3D mbedtls_md_info_from_type (MBEDTLS_MD_SHA256); + HashLen =3D mbedtls_md_get_size (MdInfo); + ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE); + mbedtls_md (MdInfo, Data, DataLen, Hash); + if (SignerInfo->AuthAttr.p !=3D NULL) { + TempAuthAttr =3D *(SignerInfo->AuthAttr.p); + *(SignerInfo->AuthAttr.p) =3D MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_= SET; + mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, = Hash); + // Restore content + *(SignerInfo->AuthAttr.p) =3D TempAuthAttr; + } + + Ret =3D mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA256, Hash, HashLen, Signer= Info->Sig.p, SignerInfo->Sig.len); + if (Ret =3D=3D 0) { + return Ret; + } + + MdInfo =3D mbedtls_md_info_from_type (MBEDTLS_MD_SHA384); + HashLen =3D mbedtls_md_get_size (MdInfo); + ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE); + mbedtls_md (MdInfo, Data, DataLen, Hash); + if (SignerInfo->AuthAttr.p !=3D NULL) { + TempAuthAttr =3D *(SignerInfo->AuthAttr.p); + *(SignerInfo->AuthAttr.p) =3D MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_= SET; + mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, = Hash); + // Restore content + *(SignerInfo->AuthAttr.p) =3D TempAuthAttr; + } + + Ret =3D mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA384, Hash, HashLen, Signer= Info->Sig.p, SignerInfo->Sig.len); + if (Ret =3D=3D 0) { + return Ret; + } + + MdInfo =3D mbedtls_md_info_from_type (MBEDTLS_MD_SHA512); + HashLen =3D mbedtls_md_get_size (MdInfo); + ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE); + mbedtls_md (MdInfo, Data, DataLen, Hash); + if (SignerInfo->AuthAttr.p !=3D NULL) { + TempAuthAttr =3D *(SignerInfo->AuthAttr.p); + *(SignerInfo->AuthAttr.p) =3D MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_= SET; + mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, = Hash); + // Restore content + *(SignerInfo->AuthAttr.p) =3D TempAuthAttr; + } + + Ret =3D mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA512, Hash, HashLen, Signer= Info->Sig.p, SignerInfo->Sig.len); + if (Ret =3D=3D 0) { + return Ret; + } + + return Ret; +} + +/** + Find signer cert in MbedtlsPkcs7SignerInfo. + + @param[in] SignerInfo MbedtlsPkcs7 SignerInfo. + @param[in] Certs MbedtlsPkcs7 SignerInfo certs. + + @retval cert Signer Cert. +**/ +STATIC +mbedtls_x509_crt * +MbedTlsPkcs7FindSignerCert ( + MbedtlsPkcs7SignerInfo *SignerInfo, + mbedtls_x509_crt *Certs + ) +{ + mbedtls_x509_crt *Cert; + + Cert =3D Certs; + while (Cert !=3D NULL) { + if ((Cert->issuer_raw.len =3D=3D SignerInfo->IssuerRaw.len) && + (CompareMem (Cert->issuer_raw.p, SignerInfo->IssuerRaw.p, Cert->is= suer_raw.len) =3D=3D 0) && + (Cert->serial.len =3D=3D SignerInfo->Serial.len) && + (CompareMem (Cert->serial.p, SignerInfo->Serial.p, Cert->serial.le= n) =3D=3D 0)) + { + break; + } + + Cert =3D Cert->next; + } + + return Cert; +} + +/** + verify cert. + + @param[in] Ca CA cert. + @param[in] CaCrl CRL. + @param[in] End Cert which need be verified. + + @retval TRUE Verify successfully. + @retval FALSE Verify failed. +**/ +STATIC +BOOLEAN +MbedTlsPkcs7VerifyCert ( + mbedtls_x509_crt *Ca, + mbedtls_x509_crl *CaCrl, + mbedtls_x509_crt *End + ) +{ + INT32 Ret; + UINT32 VFlag; + mbedtls_x509_crt_profile Profile; + + VFlag =3D 0; + CopyMem (&Profile, &gCompatProfile, sizeof (mbedtls_x509_crt_profile)); + + Ret =3D mbedtls_x509_crt_verify_with_profile (End, Ca, CaCrl, &Profile, = NULL, &VFlag, NULL, NULL); + + return Ret =3D=3D 0; +} + +/** + verify cert chain. + + @param[in] Pkcs7 MbedtlsPkcs7. + @param[in] Ca CA cert. + @param[in] End Cert which need be verified. + + @retval TRUE Verify successfully. + @retval FALSE Verify failed. +**/ +STATIC +BOOLEAN +MbedTlsPkcs7VerifyCertChain ( + MbedtlsPkcs7 *Pkcs7, + mbedtls_x509_crt *Ca, + mbedtls_x509_crt *End + ) +{ + mbedtls_x509_crt *AllCert; + mbedtls_x509_crt *InterCert; + + AllCert =3D &(Pkcs7->SignedData.Certificates); + InterCert =3D NULL; + + while (AllCert !=3D NULL) { + if ((AllCert->next =3D=3D End) && (MbedTlsPkcs7VerifyCert (AllCert, NU= LL, End))) { + InterCert =3D AllCert; + break; + } + + AllCert =3D AllCert->next; + } + + if (InterCert =3D=3D NULL) { + return FALSE; + } + + if (MbedTlsPkcs7VerifyCert (Ca, &(Pkcs7->SignedData.Crls), InterCert)) { + return TRUE; + } else { + return MbedTlsPkcs7VerifyCertChain (Pkcs7, Ca, InterCert); + } +} + +/** + MbedTlsPkcs7 Verify SignedData. + + @param[in] Pkcs7 MbedtlsPkcs7. + @param[in] TrustCert CA cert. + @param[in] Data Pointer for data. + @param[in] DataLen The len the buffer. + + @retval TRUE Verify successfully. + @retval FALSE Verify failed. +**/ +STATIC +BOOLEAN +MbedTlsPkcs7SignedDataVerify ( + MbedtlsPkcs7 *Pkcs7, + mbedtls_x509_crt *TrustCert, + CONST UINT8 *Data, + INTN DataLen + ) +{ + MbedtlsPkcs7SignerInfo *SignerInfo; + mbedtls_x509_crt *Cert; + mbedtls_x509_crt *AllCert; + BOOLEAN Result; + + SignerInfo =3D &(Pkcs7->SignedData.SignerInfos); + Result =3D TRUE; + + // + // Traverse signers and verify each signers + // + while (SignerInfo !=3D NULL) { + Result =3D FALSE; + // 1. Find signers cert + Cert =3D MbedTlsPkcs7FindSignerCert (SignerInfo, &(Pkcs7->SignedData.C= ertificates)); + if (Cert !=3D NULL) { + // 2. Check signer cert is trusted by trustCert + if (MbedTlsPkcs7VerifyCert (TrustCert, &(Pkcs7->SignedData.Crls), Ce= rt)) { + // root cert verify pass + Result =3D TRUE; + } else { + if (MbedTlsPkcs7VerifyCertChain (Pkcs7, TrustCert, Cert)) { + Result =3D TRUE; + } else { + Result =3D FALSE; + } + } + + if (Result =3D=3D TRUE) { + // 3. Check signed data + AllCert =3D &(Pkcs7->SignedData.Certificates); + while (AllCert !=3D NULL) { + if (MbedtlsPkcs7SignedDataVerifySigners (SignerInfo, AllCert, Da= ta, DataLen) =3D=3D 0) { + return TRUE; + } + + AllCert =3D AllCert->next; + } + + Result =3D FALSE; + } + } + + // move to next + SignerInfo =3D SignerInfo->Next; + } + + return Result; +} + +/** + Check input P7Data is a wrapped ContentInfo structure or not. If not con= struct + a new structure to wrap P7Data. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do = basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, othe= rwise + return FALSE. + @param[out] WrapData If return status of this function is TRUE: + 1) when WrapFlag is TRUE, pointer to P7Data. + 2) when WrapFlag is FALSE, pointer to a new Con= tentInfo + structure. It's caller's responsibility to free= this + buffer. + @param[out] WrapDataSize Length of ContentInfo structure in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE The operation is failed due to lack of resource= s. + +**/ +BOOLEAN +WrapPkcs7Data ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT BOOLEAN *WrapFlag, + OUT UINT8 **WrapData, + OUT UINTN *WrapDataSize + ) +{ + BOOLEAN Wrapped; + UINT8 *SignedData; + + // + // Check whether input P7Data is a wrapped ContentInfo structure or not. + // + Wrapped =3D FALSE; + if ((P7Data[4] =3D=3D 0x06) && (P7Data[5] =3D=3D 0x09)) { + if (CompareMem (P7Data + 6, MBEDTLS_OID_PKCS7_SIGNED_DATA, sizeof (MBE= DTLS_OID_PKCS7_SIGNED_DATA) - 1) =3D=3D 0) { + if ((P7Data[15] =3D=3D 0xA0) && (P7Data[16] =3D=3D 0x82)) { + Wrapped =3D TRUE; + } + } + } + + if (Wrapped) { + *WrapData =3D (UINT8 *)P7Data; + *WrapDataSize =3D P7Length; + } else { + // + // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in= 19 bytes. + // + *WrapDataSize =3D P7Length + 19; + *WrapData =3D AllocateZeroPool (*WrapDataSize); + if (*WrapData =3D=3D NULL) { + *WrapFlag =3D Wrapped; + return FALSE; + } + + SignedData =3D *WrapData; + + // + // Part1: 0x30, 0x82. + // + SignedData[0] =3D 0x30; + SignedData[1] =3D 0x82; + + // + // Part2: Length1 =3D P7Length + 19 - 4, in big endian. + // + SignedData[2] =3D (UINT8)(((UINT16)(*WrapDataSize - 4)) >> 8); + SignedData[3] =3D (UINT8)(((UINT16)(*WrapDataSize - 4)) & 0xff); + + // + // Part3: 0x06, 0x09. + // + SignedData[4] =3D 0x06; + SignedData[5] =3D 0x09; + + // + // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02. + // + CopyMem (SignedData + 6, MBEDTLS_OID_PKCS7_SIGNED_DATA, sizeof (MBEDTL= S_OID_PKCS7_SIGNED_DATA) - 1); + + // + // Part5: 0xA0, 0x82. + // + SignedData[15] =3D 0xA0; + SignedData[16] =3D 0x82; + + // + // Part6: Length2 =3D P7Length, in big endian. + // + SignedData[17] =3D (UINT8)(((UINT16)P7Length) >> 8); + SignedData[18] =3D (UINT8)(((UINT16)P7Length) & 0xff); + + // + // Part7: P7Data. + // + CopyMem (SignedData + 19, P7Data, P7Length); + } + + *WrapFlag =3D Wrapped; + return TRUE; +} + +/** + Verifies the validity of a PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be w= rapped + in a ContentInfo structure. + + If P7Data, TrustedCert or InData is NULL, then return FALSE. + If P7Length, CertLength or DataLength overflow, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[in] TrustedCert Pointer to a trusted/root certificate encoded i= n DER, which + is used for certificate chain verification. + @param[in] CertLength Length of the trusted certificate in bytes. + @param[in] InData Pointer to the content to be verified. + @param[in] DataLength Length of InData in bytes. + + @retval TRUE The specified PKCS#7 signed data is valid. + @retval FALSE Invalid PKCS#7 signed data. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7Verify ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + IN CONST UINT8 *TrustedCert, + IN UINTN CertLength, + IN CONST UINT8 *InData, + IN UINTN DataLength + ) +{ + BOOLEAN Status; + UINT8 *WrapData; + UINTN WrapDataSize; + BOOLEAN Wrapped; + MbedtlsPkcs7 Pkcs7; + INT32 Ret; + mbedtls_x509_crt Crt; + + Status =3D WrapPkcs7Data (P7Data, P7Length, &Wrapped, &WrapData, &WrapDa= taSize); + + if (Status) { + Ret =3D 0; + Status =3D FALSE; + } else { + Ret =3D -1; + } + + MbedTlsPkcs7Init (&Pkcs7); + mbedtls_x509_crt_init (&Crt); + + if (Ret =3D=3D 0) { + Ret =3D MbedtlsPkcs7ParseDer (WrapData, (INT32)WrapDataSize, &Pkcs7); + } + + if (Ret =3D=3D 0) { + Ret =3D mbedtls_x509_crt_parse_der (&Crt, TrustedCert, CertLength); + } + + if (Ret =3D=3D 0) { + Status =3D MbedTlsPkcs7SignedDataVerify (&Pkcs7, &Crt, InData, (INT32)= DataLength); + } + + if (&Crt !=3D NULL) { + mbedtls_x509_crt_free (&Crt); + } + + return Status; +} + +/** + Wrap function to use free() to free allocated memory for certificates. + + @param[in] Certs Pointer to the certificates to be freed. + +**/ +VOID +EFIAPI +Pkcs7FreeSigners ( + IN UINT8 *Certs + ) +{ + if (Certs =3D=3D NULL) { + return; + } + + FreePool (Certs); +} + +/** + Get the signer's certificates from PKCS#7 signed data as described in "P= KCS #7: + Cryptographic Message Syntax Standard". The input signed data could be w= rapped + in a ContentInfo structure. + + If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, th= en + return FALSE. If P7Length overflow, then return FALSE. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do = basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] CertStack Pointer to Signer's certificates retrieved from= P7Data. + It's caller's responsibility to free the buffer= with + Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] StackLength Length of signer's certificates in bytes. + @param[out] TrustedCert Pointer to a trusted certificate from Signer's = certificates. + It's caller's responsibility to free the buffer= with + Pkcs7FreeSigners(). + @param[out] CertLength Length of the trusted certificate in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSigners ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **CertStack, + OUT UINTN *StackLength, + OUT UINT8 **TrustedCert, + OUT UINTN *CertLength + ) +{ + MbedtlsPkcs7SignerInfo *SignerInfo; + mbedtls_x509_crt *Cert; + MbedtlsPkcs7 Pkcs7; + BOOLEAN Status; + UINT8 *WrapData; + UINTN WrapDataSize; + BOOLEAN Wrapped; + + UINTN CertSize; + UINT8 Index; + UINT8 *CertBuf; + UINT8 *OldBuf; + UINTN BufferSize; + UINTN OldSize; + + if ((P7Data =3D=3D NULL) || (CertStack =3D=3D NULL) || (StackLength =3D= =3D NULL) || + (TrustedCert =3D=3D NULL) || (CertLength =3D=3D NULL) || (P7Length >= INT_MAX)) + { + return FALSE; + } + + Status =3D WrapPkcs7Data (P7Data, P7Length, &Wrapped, &WrapData, &WrapDa= taSize); + + if (!Status) { + return FALSE; + } + + Status =3D FALSE; + CertBuf =3D NULL; + OldBuf =3D NULL; + Cert =3D NULL; + + MbedTlsPkcs7Init (&Pkcs7); + if (MbedtlsPkcs7ParseDer (WrapData, (INT32)WrapDataSize, &Pkcs7) !=3D 0)= { + goto _Exit; + } + + SignerInfo =3D &(Pkcs7.SignedData.SignerInfos); + + // + // Traverse each signers + // + // Convert CertStack to buffer in following format: + // UINT8 CertNumber; + // UINT32 Cert1Length; + // UINT8 Cert1[]; + // UINT32 Cert2Length; + // UINT8 Cert2[]; + // ... + // UINT32 CertnLength; + // UINT8 Certn[]; + // + BufferSize =3D sizeof (UINT8); + OldSize =3D BufferSize; + Index =3D 0; + + while (SignerInfo !=3D NULL) { + // Find signers cert + Cert =3D MbedTlsPkcs7FindSignerCert (SignerInfo, &(Pkcs7.SignedData.Ce= rtificates)); + if (Cert =3D=3D NULL) { + goto _Exit; + } + + CertSize =3D Cert->raw.len; + OldSize =3D BufferSize; + OldBuf =3D CertBuf; + BufferSize =3D OldSize + CertSize + sizeof (UINT32); + + CertBuf =3D AllocateZeroPool (BufferSize); + if (CertBuf =3D=3D NULL) { + goto _Exit; + } + + if (OldBuf !=3D NULL) { + CopyMem (CertBuf, OldBuf, OldSize); + free (OldBuf); + OldBuf =3D NULL; + } + + WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)CertSize); + CopyMem (CertBuf + OldSize + sizeof (UINT32), Cert->raw.p, CertSize); + + Index++; + + // move to next + SignerInfo =3D SignerInfo->Next; + } + + if (CertBuf !=3D NULL) { + // + // Update CertNumber. + // + CertBuf[0] =3D Index; + + *CertLength =3D BufferSize - OldSize - sizeof (UINT32); + *TrustedCert =3D AllocateZeroPool (*CertLength); + if (*TrustedCert =3D=3D NULL) { + goto _Exit; + } + + CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLengt= h); + *CertStack =3D CertBuf; + *StackLength =3D BufferSize; + Status =3D TRUE; + } + +_Exit: + // + // Release Resources + // + if (!Status && (CertBuf !=3D NULL)) { + FreePool (CertBuf); + *CertStack =3D NULL; + } + + if (OldBuf !=3D NULL) { + FreePool (OldBuf); + } + + return Status; +} + +/** + Retrieves all embedded certificates from PKCS#7 signed data as described= in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate list= s chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SignerChainCerts Pointer to the certificates list chained t= o signer's + certificate. It's caller's responsibility = to free the buffer + with Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type= . + @param[out] ChainLength Length of the chained certificates list bu= ffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates list= s. It's caller's + responsibility to free the buffer with Pkc= s7FreeSigners(). + This data structure is EFI_CERT_STACK type= . + @param[out] UnchainLength Length of the unchained certificates list = buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c= b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c new file mode 100644 index 0000000000..23ea676373 --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c @@ -0,0 +1,689 @@ +/** @file + This module verifies that Enhanced Key Usages (EKU's) are present within + a PKCS7 signature blob using MbedTLS. + + Copyright (C) Microsoft Corporation. All Rights Reserved. + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include "InternalCryptLib.h" +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 EkuOID[] =3D { 0x55, 0x1D, 0x25= }; + +/*leaf Cert basic_constraints case1: CA: false and CA object is excluded *= / +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gBasicConstraintsCase1[] =3D { = 0x30, 0x00 }; + +/*leaf Cert basic_constraints case2: CA: false */ +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gBasicConstraintsCase2[] =3D { = 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00 }; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gOidBasicConstraints[] =3D { 0x= 55, 0x1D, 0x13 }; + +/** + Find first Extension data match with given OID + + @param[in] Start Pointer to the DER-encoded extensions = data + @param[in] End extensions data size in bytes + @param[in ] Oid OID for match + @param[in ] OidSize OID size in bytes + @param[out] FindExtensionData output matched extension data. + @param[out] FindExtensionDataLen matched extension data size. + +**/ +STATIC +BOOLEAN +InternalX509FindExtensionData ( + UINT8 *Start, + UINT8 *End, + CONST UINT8 *Oid, + UINTN OidSize, + UINT8 **FindExtensionData, + UINTN *FindExtensionDataLen + ) +{ + UINT8 *Ptr; + UINT8 *ExtensionPtr; + UINTN ObjLen; + INT32 Ret; + BOOLEAN Status; + UINTN FindExtensionLen; + UINTN HeaderLen; + + /*If no Extension entry match Oid*/ + Status =3D FALSE; + Ptr =3D Start; + + Ret =3D 0; + + while (TRUE) { + // + // Extension ::=3D SEQUENCE { + // extnID OBJECT IDENTIFIER, + // critical BOOLEAN DEFAULT FALSE, + // extnValue OCTET STRING } + // + ExtensionPtr =3D Ptr; + Ret =3D mbedtls_asn1_get_tag ( + &Ptr, + End, + &ObjLen, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE + ); + if (Ret =3D=3D 0) { + HeaderLen =3D (UINTN)(Ptr - ExtensionPtr); + FindExtensionLen =3D ObjLen; + /* Get Object Identifier*/ + Ret =3D mbedtls_asn1_get_tag ( + &Ptr, + End, + &ObjLen, + MBEDTLS_ASN1_OID + ); + } else { + break; + } + + if ((Ret =3D=3D 0) && !CompareMem (Ptr, Oid, OidSize)) { + Ptr +=3D ObjLen; + + Ret =3D mbedtls_asn1_get_tag ( + &Ptr, + End, + &ObjLen, + MBEDTLS_ASN1_BOOLEAN + ); + if (Ret =3D=3D 0) { + Ptr +=3D ObjLen; + } + + Ret =3D mbedtls_asn1_get_tag ( + &Ptr, + End, + &ObjLen, + MBEDTLS_ASN1_OCTET_STRING + ); + } else { + Ret =3D 1; + } + + if (Ret =3D=3D 0) { + *FindExtensionData =3D Ptr; + *FindExtensionDataLen =3D ObjLen; + Status =3D TRUE; + break; + } + + /* move to next*/ + Ptr =3D ExtensionPtr + HeaderLen + FindExtensionLen; + Ret =3D 0; + } + + return Status; +} + +/** + Retrieve Extension data from one X.509 certificate. + + @param[in] Cert Pointer to the X509 certificate. + @param[in] Oid Object identifier buffer + @param[in] OidSize Object identifier buffer size + @param[out] ExtensionData Extension bytes. + @param[in, out] ExtensionDataSize Extension bytes size. + + @retval RETURN_SUCCESS The certificate Extension data retrieve= d successfully. + @retval RETURN_INVALID_PARAMETER If Cert is NULL. + If ExtensionDataSize is NULL. + If ExtensionData is not NULL and *Extens= ionDataSize is 0. + If Certificate is invalid. + @retval RETURN_NOT_FOUND If no Extension entry match Oid. + @retval RETURN_BUFFER_TOO_SMALL If the ExtensionData is NULL. The requi= red buffer size + is returned in the ExtensionDataSize par= ameter. + @retval RETURN_UNSUPPORTED The operation is not supported. +**/ +STATIC +BOOLEAN +GetExtensionData ( + CONST mbedtls_x509_crt *Cert, + CONST UINT8 *Oid, + UINTN OidSize, + UINT8 *ExtensionData, + UINTN *ExtensionDataSize + ) +{ + CONST mbedtls_x509_crt *Crt; + INT32 Ret; + BOOLEAN Status; + UINT8 *Ptr; + UINT8 *End; + UINTN ObjLen; + + Ptr =3D NULL; + End =3D NULL; + ObjLen =3D 0; + + if ((Cert =3D=3D NULL) || (Oid =3D=3D NULL) || (OidSize =3D=3D 0) || + (ExtensionDataSize =3D=3D NULL)) + { + return FALSE; + } + + Status =3D FALSE; + + Crt =3D Cert; + + Ptr =3D Crt->v3_ext.p; + End =3D Crt->v3_ext.p + Crt->v3_ext.len; + Ret =3D mbedtls_asn1_get_tag ( + &Ptr, + End, + &ObjLen, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE + ); + + if (Ret =3D=3D 0) { + Status =3D InternalX509FindExtensionData ( + Ptr, + End, + Oid, + OidSize, + &Ptr, + &ObjLen + ); + } + + if (Status) { + if (*ExtensionDataSize < ObjLen) { + *ExtensionDataSize =3D ObjLen; + Status =3D FALSE; + goto cleanup; + } + + if (Oid !=3D NULL) { + if (ExtensionData =3D=3D NULL) { + return FALSE; + } + + CopyMem (ExtensionData, Ptr, ObjLen); + } + + *ExtensionDataSize =3D ObjLen; + } else { + *ExtensionDataSize =3D 0; + } + +cleanup: + return Status; +} + +/** + Determines if the specified EKU represented in ASN1 form is present + in a given certificate. + + @param[in] Cert The certificate to check. + @param[in] EKU The EKU to look for. + @param[in] EkuLen The size of EKU. + + @retval EFI_SUCCESS We successfully identified the signing= type. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in th= e signature. + +**/ +STATIC +EFI_STATUS +IsEkuInCertificate ( + IN CONST mbedtls_x509_crt *Cert, + IN UINT8 *EKU, + IN UINTN EkuLen + ) +{ + EFI_STATUS Status; + BOOLEAN Ret; + UINT8 *Buffer; + UINTN Index; + UINTN Len; + + if ((Cert =3D=3D NULL) || (EKU =3D=3D NULL)) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + Len =3D 0; + Buffer =3D NULL; + Ret =3D GetExtensionData ( + Cert, + (CONST UINT8 *)EkuOID, + sizeof (EkuOID), + NULL, + &Len + ); + if (Len =3D=3D 0) { + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + Buffer =3D AllocateZeroPool (Len); + if (Buffer =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + Ret =3D GetExtensionData ( + Cert, + (CONST UINT8 *)EkuOID, + sizeof (EkuOID), + Buffer, + &Len + ); + + if ((Len =3D=3D 0) || (!Ret)) { + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + Status =3D EFI_NOT_FOUND; + /*find the spdm hardware identity OID*/ + for (Index =3D 0; Index <=3D Len - EkuLen; Index++) { + if (!CompareMem (Buffer + Index, EKU, EkuLen)) { + // check sub EKU + if (Index =3D=3D Len - EkuLen) { + Status =3D EFI_SUCCESS; + break; + // Ensure that the OID is complete + } else if (Buffer[Index + EkuLen] =3D=3D 0x06) { + Status =3D EFI_SUCCESS; + break; + } else { + break; + } + } + } + +Exit: + if (Buffer !=3D NULL) { + FreePool (Buffer); + } + + return Status; +} + +/** + Get OID from txt. + + @param[in] RequiredEKUs Array of null-terminated strings listin= g OIDs of + required EKUs that must be present in t= he signature. + @param[in] RequiredEKUsSize Number of elements in the RequiredEKUs = string array. + @param[in,out] CheckOid OID. + @param[out] OidLen The size of OID. + +**/ +void +GetOidFromTxt ( + IN CONST CHAR8 *RequiredEKUs, + IN UINTN RequiredEKUsSize, + IN OUT UINT8 *CheckOid, + OUT UINT8 *OidLen + ) +{ + UINT8 *Ptr; + UINT16 Index; + UINT32 Data; + UINT8 OidIndex; + UINTN EKUsSize; + + EKUsSize =3D RequiredEKUsSize; + // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-o= bject-identifier?redirectedfrom=3DMSDN + CheckOid[0] =3D (UINT8)((RequiredEKUs[0] - '0') * 40 + (RequiredEKUs[2] = - '0')); + + EKUsSize =3D EKUsSize - 4; + Ptr =3D (UINT8 *)(RequiredEKUs + 4); + + OidIndex =3D 1; + + while (EKUsSize) { + Index =3D 0; + Data =3D 0; + + while ((*Ptr !=3D '.') && (*Ptr !=3D '\0')) { + Index++; + Ptr++; + EKUsSize--; + } + + while (Index) { + Data =3D 10 * Data + (*(Ptr - Index) - '0'); + Index--; + } + + if (EKUsSize !=3D 0) { + Ptr++; + EKUsSize--; + } + + if (Data < 128) { + CheckOid[OidIndex] =3D (UINT8)Data; + OidIndex++; + } else { + CheckOid[OidIndex + 1] =3D (UINT8)(Data & 0xFF); + CheckOid[OidIndex] =3D (UINT8)(((((Data & 0xFF00) << 1) | 0x8000= ) >> 8) & 0xFF); + OidIndex =3D OidIndex + 2; + } + } + + *OidLen =3D OidIndex; +} + +/** + Verify the Cert is signer cert + + @param[in] Start Pointer to the DER-encoded certificate data Sta= rt. + @param[in] End Pointer to the DER-encoded certificate data End= . + + @retval true verify pass + @retval false verify fail +**/ +STATIC +BOOLEAN +IsCertSignerCert ( + UINT8 *Start, + UINT8 *End + ) +{ + BOOLEAN Status; + UINT8 *Buffer; + UINTN Len; + mbedtls_x509_crt Cert; + UINTN ObjLen; + + mbedtls_x509_crt_init (&Cert); + + ObjLen =3D End - Start; + + if (mbedtls_x509_crt_parse_der (&Cert, Start, ObjLen) !=3D 0) { + return FALSE; + } + + Len =3D 0; + Buffer =3D NULL; + Status =3D GetExtensionData ( + &Cert, + (CONST UINT8 *)gOidBasicConstraints, + sizeof (gOidBasicConstraints), + NULL, + &Len + ); + if (Len =3D=3D 0) { + /* basic constraints is not present in Cert */ + return TRUE; + } + + Buffer =3D AllocateZeroPool (Len); + if (Buffer =3D=3D NULL) { + return FALSE; + } + + Status =3D GetExtensionData ( + &Cert, + (CONST UINT8 *)gOidBasicConstraints, + sizeof (gOidBasicConstraints), + Buffer, + &Len + ); + + if (Len =3D=3D 0) { + /* basic constraints is not present in Cert */ + Status =3D TRUE; + goto Exit; + } else if (!Status) { + Status =3D FALSE; + goto Exit; + } + + if ((Len =3D=3D sizeof (gBasicConstraintsCase1)) && + (!CompareMem (Buffer, gBasicConstraintsCase1, sizeof (gBasicConstrai= ntsCase1)))) + { + Status =3D TRUE; + goto Exit; + } + + if ((Len =3D=3D sizeof (gBasicConstraintsCase2)) && + (!CompareMem (Buffer, gBasicConstraintsCase2, sizeof (gBasicConstrai= ntsCase2)))) + { + Status =3D TRUE; + goto Exit; + } + + Status =3D FALSE; + +Exit: + mbedtls_x509_crt_free (&Cert); + + if (Buffer !=3D NULL) { + FreePool (Buffer); + } + + return Status; +} + +/** + Determines if the specified EKUs are present in a signing certificate. + + @param[in] SignerCert The certificate to check. + @param[in] RequiredEKUs The EKUs to look for. + @param[in] RequiredEKUsSize The number of EKUs + @param[in] RequireAllPresent If TRUE, then all the specified EKUs + must be present in the certificate. + + @retval EFI_SUCCESS We successfully identified the signing= type. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in th= e signature. +**/ +STATIC +EFI_STATUS +CheckEKUs ( + IN CONST mbedtls_x509_crt *SignerCert, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + EFI_STATUS Status; + UINT32 NumEkusFound; + UINT32 Index; + UINT8 *EKU; + UINTN EkuLen; + UINT8 CheckOid[20]; + UINT8 OidLen; + + Status =3D EFI_SUCCESS; + NumEkusFound =3D 0; + + if ((SignerCert =3D=3D NULL) || (RequiredEKUs =3D=3D NULL) || (RequiredE= KUsSize =3D=3D 0)) { + Status =3D EFI_INVALID_PARAMETER; + goto Exit; + } + + for (Index =3D 0; Index < RequiredEKUsSize; Index++) { + // + // Finding required EKU in Cert. + // + GetOidFromTxt (RequiredEKUs[Index], strlen (RequiredEKUs[Index]), Chec= kOid, &OidLen); + + EKU =3D CheckOid; + EkuLen =3D OidLen; + + Status =3D IsEkuInCertificate (SignerCert, EKU, EkuLen); + if (Status =3D=3D EFI_SUCCESS) { + NumEkusFound++; + if (!RequireAllPresent) { + // + // Found at least one, so we are done. + // + goto Exit; + } + } else { + // + // Fail to find Eku in Cert + break; + } + } + +Exit: + if (RequireAllPresent && + (NumEkusFound =3D=3D RequiredEKUsSize)) + { + // + // Found all required EKUs in certificate. + // + Status =3D EFI_SUCCESS; + } + + return Status; +} + +/** + This function receives a PKCS#7 formatted signature blob, + looks for the EKU SEQUENCE blob, and if found then looks + for all the required EKUs. This function was created so that + the Surface team can cut down on the number of Certificate + Authorities (CA's) by checking EKU's on leaf signers for + a specific product. This prevents one product's certificate + from signing another product's firmware or unlock blobs. + + Note that this function does not validate the certificate chain. + That needs to be done before using this function. + + @param[in] Pkcs7Signature The PKCS#7 signed information content b= lock. An array + containing the content block with both = the signature, + the signer's certificate, and any neces= sary intermediate + certificates. + @param[in] Pkcs7SignatureSize Number of bytes in Pkcs7Signature. + @param[in] RequiredEKUs Array of null-terminated strings listin= g OIDs of + required EKUs that must be present in t= he signature. + @param[in] RequiredEKUsSize Number of elements in the RequiredEKUs = string array. + @param[in] RequireAllPresent If this is TRUE, then all of the specif= ied EKU's + must be present in the leaf signer. If= it is + FALSE, then we will succeed if we find = any + of the specified EKU's. + + @retval EFI_SUCCESS The required EKUs were found in the sig= nature. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the= signature. + +**/ +EFI_STATUS +EFIAPI +VerifyEKUsInPkcs7Signature ( + IN CONST UINT8 *Pkcs7Signature, + IN CONST UINT32 SignatureSize, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + EFI_STATUS Status; + mbedtls_x509_crt Cert; + UINT8 *Ptr; + UINT8 *End; + INT32 Len; + UINTN ObjLen; + UINT8 *OldEnd; + + // + // Check input parameter. + // + if ((RequiredEKUs =3D=3D NULL) || (Pkcs7Signature =3D=3D NULL)) { + Status =3D EFI_INVALID_PARAMETER; + return Status; + } + + mbedtls_x509_crt_init (&Cert); + + Ptr =3D (UINT8 *)(UINTN)Pkcs7Signature; + Len =3D (UINT32)SignatureSize; + End =3D Ptr + Len; + + // Cert + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED |= MBEDTLS_ASN1_SEQUENCE) !=3D 0) { + return FALSE; + } + + // tbscert + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) !=3D= 0) { + return FALSE; + } + + Ptr +=3D ObjLen; + // signature algo + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED |= MBEDTLS_ASN1_SET) !=3D 0) { + return FALSE; + } + + Ptr +=3D ObjLen; + // signature + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED |= MBEDTLS_ASN1_SEQUENCE) !=3D 0) { + return FALSE; + } + + Ptr +=3D ObjLen; + OldEnd =3D Ptr; + // Cert + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED |= MBEDTLS_ASN1_CONTEXT_SPECIFIC) !=3D 0) { + return FALSE; + } + + End =3D Ptr + ObjLen; + + // leaf Cert + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED |= MBEDTLS_ASN1_SEQUENCE) !=3D 0) { + return FALSE; + } + + Ptr +=3D ObjLen; + + while ((Ptr !=3D End) && (Ptr < End)) { + if (IsCertSignerCert (OldEnd, Ptr)) { + break; + } + + OldEnd =3D Ptr; + if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED= | MBEDTLS_ASN1_SEQUENCE) !=3D 0) { + return FALSE; + } + + Ptr +=3D ObjLen; + } + + if (Ptr !=3D End) { + return FALSE; + } else { + Ptr =3D End - ObjLen; + } + + // leaf Cert + ObjLen +=3D Ptr - OldEnd; + Ptr =3D OldEnd; + + if (mbedtls_x509_crt_parse_der (&Cert, Ptr, ObjLen) !=3D 0) { + return FALSE; + } + + Status =3D CheckEKUs (&Cert, RequiredEKUs, RequiredEKUsSize, RequireAllP= resent); + if (Status !=3D EFI_SUCCESS) { + goto Exit; + } + +Exit: + // + // Release Resources + // + mbedtls_x509_crt_free (&Cert); + + return Status; +} --=20 2.26.2.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118072): https://edk2.groups.io/g/devel/message/118072 Mute This Topic: https://groups.io/mt/105552835/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-