python / python/cpython

Email's as_bytes() method unfolds a protected header in a pgp signed message part breaking the signature.

オープン
#153,822 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

stdlib topic-email type-bug
主要言語
Python
スター
77.2k
フォーク
35.9k
PR マージ指標
PR 指標を取得中

説明

Bug report

Bug description:
>>> from email import parser, policy
>>> # Create a bytes parser with default policy
>>> parser = parser.BytesParser(policy=policy.default)
>>> # Set bytes to the raw message content. Note the In-Reply-To header is folded in both the outer message
>>> # and in the proctected headers in the signed text/plain part.
>>> bytes = b"""In-Reply-To:
...  <CAMFngpXc_66qL0nUkHtT5g98BhWHPE8-KFtc6=87OvA-U7O9cw@mail.gmail.com>
... MIME-Version: 1.0
... Content-Type: multipart/signed; boundary="nextPartVzbFsyfPQFC9aKXYcHllLg";
...  micalg="pgp-sha512"; protocol="application/pgp-signature"
... 
... --nextPartVzbFsyfPQFC9aKXYcHllLg
... Content-Transfer-Encoding: 7Bit
... Content-Type: text/plain; charset="utf-8"; protected-headers="v1"
... In-Reply-To:
...  <CAMFngpXc_66qL0nUkHtT5g98BhWHPE8-KFtc6=87OvA-U7O9cw@mail.gmail.com>
... MIME-Version: 1.0
... 
... fake message here
... --nextPartVzbFsyfPQFC9aKXYcHllLg
... Content-Type: application/pgp-signature; name="signature.asc"
... Content-Description: This is a digitally signed message part.
... Content-Transfer-Encoding: 7Bit
... 
... -----BEGIN PGP SIGNATURE-----
... 
... iJEEABYKADkWIQRIePpI7xqJT+Ra2G9Prbu26Vsl/AUCalfydhsUgAAAAAAEAA5t
... YW51MiwyLjUrMS4xMiwyLDIACgkQT627tulbJfzupAD/a1gphNvf7nc+sYph/EJi
... W61+Kg356YYzRXS7SsfFI14A/2z4u28/Chqd/ETNh4VRYfl4Rf8N7eDMpFOZSEdM
... bTkF
... =QWJd
... -----END PGP SIGNATURE-----
... 
... --nextPartVzbFsyfPQFC9aKXYcHllLg--
... """
>>> # Create a message object.
>>> msg = parser.parsebytes(bytes)
>>> # and print its as_bytes() representation.
>>> print(msg.as_bytes().decode())
In-Reply-To:
 <CAMFngpXc_66qL0nUkHtT5g98BhWHPE8-KFtc6=87OvA-U7O9cw@mail.gmail.com>
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="nextPartVzbFsyfPQFC9aKXYcHllLg";
 micalg="pgp-sha512"; protocol="application/pgp-signature"

--nextPartVzbFsyfPQFC9aKXYcHllLg
Content-Transfer-Encoding: 7Bit
Content-Type: text/plain; charset="utf-8"; protected-headers="v1"
In-Reply-To: <CAMFngpXc_66qL0nUkHtT5g98BhWHPE8-KFtc6=87OvA-U7O9cw@mail.gmail.com>
MIME-Version: 1.0

fake message here
--nextPartVzbFsyfPQFC9aKXYcHllLg
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: This is a digitally signed message part.
Content-Transfer-Encoding: 7Bit

-----BEGIN PGP SIGNATURE-----

iJEEABYKADkWIQRIePpI7xqJT+Ra2G9Prbu26Vsl/AUCalfydhsUgAAAAAAEAA5t
YW51MiwyLjUrMS4xMiwyLDIACgkQT627tulbJfzupAD/a1gphNvf7nc+sYph/EJi
W61+Kg356YYzRXS7SsfFI14A/2z4u28/Chqd/ETNh4VRYfl4Rf8N7eDMpFOZSEdM
bTkF
=QWJd
-----END PGP SIGNATURE-----

--nextPartVzbFsyfPQFC9aKXYcHllLg--

>>> # Note that the protected In-Reply-To header in the signed text/plain part is unfolded even though it is
>>> # 81 bytes long.
>>> # Now get only the text/plain part.
>>> part = msg.get_payload(0)
>>> # And see it as_bytes().
>>> print(part.as_bytes().decode())
Content-Transfer-Encoding: 7Bit
Content-Type: text/plain; charset="utf-8"; protected-headers="v1"
In-Reply-To:
 <CAMFngpXc_66qL0nUkHtT5g98BhWHPE8-KFtc6=87OvA-U7O9cw@mail.gmail.com>
MIME-Version: 1.0

fake message here
>>> # And here the header is properly folded.

The problem here is if a message of which the above is an excerpt is received by some application, e.g. Mailman, and later resent to recipients by passing the message object to Python's smtplib.SMTP.send_message() method which serializes the message with the as_bytes() method applied to the whole message, the resent message has the unfolded protected In-Reply-To header in the signed part breaking the signature.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs
  • gh-154107

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

レポートにある BytesParser と Message.as_bytes() の再現から始め、次に smtplib.SMTP.send_message() を通じたシリアライズを追跡します。multipart/signed メッセージがシリアライズされる際に、保護された In-Reply-To ヘッダーが折り返されたままであることを確認し、元の署名が無効化されないようにします。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
backend
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
30/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。