From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1nvhoW-0002N2-7R for mharc-grub-devel@gnu.org; Mon, 30 May 2022 12:00:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:37096) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nvhoQ-0002Kf-2N for grub-devel@gnu.org; Mon, 30 May 2022 12:00:10 -0400 Received: from out4-smtp.messagingengine.com ([66.111.4.28]:47463) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nvhoK-0005qB-2X for grub-devel@gnu.org; Mon, 30 May 2022 12:00:09 -0400 Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id 736985C01D6; Mon, 30 May 2022 12:00:01 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Mon, 30 May 2022 12:00:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:date:date:from:from:in-reply-to:message-id :mime-version:reply-to:sender:subject:subject:to:to; s=fm1; t= 1653926401; x=1654012801; bh=sJhbFV/tYifgP9gVZLVKmQ7te2YDRTWTioy 2wHe0mA4=; b=U0J9FP5J/gKw4NXHv6flryqbBrn5rlyjW7S/O/Q3a6m7eJmHLq4 9tNymnBEee8NB6vAcJCuDOLEWYEXd4GVjUYqkQVqIzatUy0Ch+TgAmAiwFEPnT8z Mnoct/wQeAIisOTCZjUvFHU3810WB0xe5ePECp8EckIrA1tuZr/m8M8Hk3GL8QBX FT4qTYqNTURh+XLBrdqdkXpt7mIfhcQmQO+nrD3DEfindcYPyJbVTMgHwtBUkigP xqb/CdgEw7jBVWGR0PGeE1l57vw3lESTDCD1BJoe/cfBkQK5PkOxipszP8nINHQJ rvfV6Sw6E+tiJUHpO6DYgL9psoy233JGk3g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:date:date:feedback-id :feedback-id:from:from:in-reply-to:message-id:mime-version :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1653926401; x= 1654012801; bh=sJhbFV/tYifgP9gVZLVKmQ7te2YDRTWTioy2wHe0mA4=; b=U Ef78yHCiEGUdMJvJGzxsclTbkEcDIlyExvxOuoCj27qXCQLqrbZgF/5tO/GVldAl 00Wk+GCG3Gd3kRIXKO3SXXzC9U03sPlqyPvbmZXBIsO5Ev4hQQVvlJnEqJvRTXRk D1U9xKWMNQwn+iFyGnXBHOiF+ZaVbrN14Fx7cVgoTUXFLBl0MDTcb6hW4X0Bsm4t eSbmTkME9PJA7uiJIkwa4wxZy6HD13cKyCCUqPx6tlN/OwUAe1we3BFBCMdayol7 Sg0SoRDC+0p5hG/chwoDI47p7bqXIpM67TdkY7LwrlMlY0fPwgdGkO8Sh6SwTKLg eYufp6XAg1M7fXDFdrqMg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrkeeigdeludcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpeffhffvvefukfggtggusehgtderredttddvnecuhfhrohhmpefrrghtrhhitghk ucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucggtffrrghtthgvrhhnpe dvfeejudduffefgfduueeuueeigfdvtdeijedufeegjeeugeeihefgteefueffheenucff ohhmrghinhepihgvthhfrdhorhhgnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrg hmpehmrghilhhfrhhomhepphhssehpkhhsrdhimh X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 30 May 2022 12:00:00 -0400 (EDT) Received: from localhost (tanuki [10.192.0.23]) by vm-mail.pks.im (OpenSMTPD) with ESMTPSA id 7c73b020 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Mon, 30 May 2022 15:59:56 +0000 (UTC) Date: Mon, 30 May 2022 18:00:56 +0200 From: Patrick Steinhardt To: grub-devel@gnu.org Cc: Daniel Kiper , Glenn Washburn Subject: [PATCH v3 0/2] luks2: Fix decoding of digests and salts with escaped chars Message-ID: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="l1yRPcuEMfMBqj5g" Content-Disposition: inline Received-SPF: pass client-ip=66.111.4.28; envelope-from=ps@pks.im; helo=out4-smtp.messagingengine.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 May 2022 16:00:11 -0000 --l1yRPcuEMfMBqj5g Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hi, this is the third version of my patch series which fixes decoding of digests and salts in LUKS2 headers in case they happen to contain escaped characters. While modern cryptsetup versions in fact don't escape any characters part of the Base64 alphabet, old versions of cryptsetup did this until v2.0.2. Changes compared to v2: - I've split out the logic to unescape JSON-escaped strings into a new `grub_json_unescape ()` function. This function now provides full support for unescaping as specified in the JSON standard. - I've converted the errors returned by `luks2_base64_decode ()` to use `grub_error ()` to provide more context. Note though that I haven't yet started to use `grub_error_push ()` as Glenn proposes: as he said, that's a more general refactoring and I thus feel like it should be part of a different patch series. - I've done my research and finally found out why this was only happening on Ubuntu 18.04, which uses cryptsetup v2.0.2, and documented this in the commit message. Patrick Patrick Steinhardt (2): json: Add function to unescape JSON-encoded strings luks2: Fix decoding of digests and salts with escaped chars grub-core/disk/luks2.c | 28 +++++++++-- grub-core/lib/json/json.c | 98 +++++++++++++++++++++++++++++++++++++++ grub-core/lib/json/json.h | 12 +++++ 3 files changed, 134 insertions(+), 4 deletions(-) Range-diff against v2: -: --------- > 1: 3055f9f2f json: Add function to unescape JSON-encoded s= trings 1: b5a9fcdb5 ! 2: 69424b2d1 luks2: Fix decoding of digests and salts with= escaped chars @@ Commit message =20 As it turns out, the root cause is that json-c, which is used by cryptsetup to read and write the JSON header, will escape some - characters by prepending a backslash when writing JSON strings. Mo= st - importantly, this also includes the forward slash, which is part o= f the - Base64 alphabet and which may optionally be escaped. Because GRUB - doesn't know to unescape such characters, decoding this string will - rightfully fail. + characters by prepending a backslash when writing JSON strings by + default. Most importantly, json-c also escapes the forward slash, = which + is part of the Base64 alphabet. Because GRUB doesn't know to unesc= ape + such characters, decoding this string will rightfully fail. =20 - Fix the issue by stripping the escape character for forward slashe= s. - There is no need to do so for any other escaped character given th= at - valid Base64 does not contain anything else. + Interestingly, this issue has until now only been reported by user= s of + Ubuntu 18.04. And a bit of digging in fact reveals that cryptsetup= has + changed the logic in a054206d (Suppress useless slash escaping in = json + lib, 2018-04-20), which has been released with cryptsetup v2.0.3. = Ubuntu + 18.04 is still shipping with cryptsetup v2.0.2 though, which expla= ins + why this is not a more frequent issue. + + Fix the issue by using our new `grub_json_unescape ()` helper func= tion + that handles unescaping for us. =20 Reported-by: Afdal Signed-off-by: Patrick Steinhardt =20 ## grub-core/disk/luks2.c ## -@@ grub-core/disk/luks2.c: luks2_scan (grub_disk_t disk, const char *c= heck_uuid, int check_boot) +@@ grub-core/disk/luks2.c: luks2_scan (grub_disk_t disk, grub_cryptomo= unt_args_t cargs) return cryptodisk; } =20 +static grub_err_t -+luks2_base64_decode (const char *in, size_t inlen, grub_uint8_t *deco= ded, size_t *decodedlen) ++luks2_base64_decode (const char *in, size_t inlen, grub_uint8_t *deco= ded, idx_t *decodedlen) +{ ++ size_t unescaped_len; + char *unescaped; + bool successful; -+ size_t i, j; + -+ unescaped =3D grub_malloc (inlen); -+ if (!unescaped) -+ return GRUB_ERR_OUT_OF_MEMORY; ++ if (grub_json_unescape (&unescaped, &unescaped_len, in, inlen) !=3D= GRUB_ERR_NONE) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not unescape Bas= e64 string"); + -+ grub_memmove (unescaped, in, inlen); -+ -+ /* -+ * Characters in JSON strings may be escaped, either via their six-= character -+ * "\uXXXX" representation or (at least for a subset of characters)= via a -+ * single backslash. In context of the Base64-encoded string we exp= ect here, -+ * the only character that gets escaped by cryptsetup is the forwar= d slash. -+ * So while incomplete, we only strip away the escape character if = we see -+ * '\/' in the input. -+ * -+ * See https://datatracker.ietf.org/doc/html/rfc8259#section-7 for = more -+ * information on escaping in JSON. -+ */ -+ for (i =3D j =3D 0; i < inlen; i++) { -+ if (i + 1 < inlen && unescaped[i] =3D=3D '\\' && unescaped[i + 1]= =3D=3D '/') -+ continue; -+ unescaped[j++] =3D unescaped[i]; -+ } -+ -+ successful =3D base64_decode (unescaped, j, (char *)decoded, decode= dlen); ++ successful =3D base64_decode (unescaped, unescaped_len, (char *)dec= oded, decodedlen); + grub_free (unescaped); + if (!successful) -+ return GRUB_ERR_BAD_ARGUMENT; ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not decode Base6= 4 string"); + + return GRUB_ERR_NONE; +} --=20 2.36.1 --l1yRPcuEMfMBqj5g Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEF9hrgiFbCdvenl/rVbJhu7ckPpQFAmKU6jgACgkQVbJhu7ck PpTM2w/9FiED2FrYvqugOaHDGDOokwaZAgnUmIAxCIy86e+5icdl+Zdk3OmxjHei PvjQIf0lreMS741S9QUerL+sYKwHt8dQ5lLcd/unIXQh+7bP96vbjhk6JV9UcI1S IYYfW6Smj0soGmVTkso/BJ07G6eGonU97ugIGOMzKFmnQmEHSAmKKfDUmg7DFehC iUJMA2Ajp0I+LkfRj22+oqja3My7/NzIao9HVUao9jajKCcawPeLH/xtoeys0+Aa P2ZUP5BobHQNd5YGcMf4ROS5TPEG/jacLFHBeJw7ZRF5TJ6dGaKo7lZ0ZzKiIatR yIBY72PvEVR5x4uLiX573YAM6CAAUnRfTBZERFL2YlMjK2DTZHlrMhmo95HXLcMr nqlTVLVJWeJKtvrQDuYSi8sIunZqg4Ieu/OY7Ba7BuDYrGtt6zKvzAFoa4zOivIk c8+CUJGxp5aYlGo8L6JICxKPEW6bJTzo283wM1FsnyGfwi9douuBZCqPodzEu/iK Xx4AAnxnyHCe1I8jygGXL9A3aRcd4+yGv5OSXe9+7CkkH1d5griH29he3eTCOmVr clw6MWSgwegOlKh2K7YTA6yyS5VDcln8OrOr1iy6GJycKVr7NLXdaGKuJc1lwuau OzGeZJlf+QSfTHmVrfl2VRi+4KG3LbT6x74l6KTKvtjSz/nN2mg= =ws2M -----END PGP SIGNATURE----- --l1yRPcuEMfMBqj5g--