diff --git a/.dockerignore b/.dockerignore index 7aa51b0..54fd6f2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,4 @@ -book/build \ No newline at end of file +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +book/build diff --git a/.gitignore b/.gitignore index df84cb6..ad3d966 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + .idea book/build/ - diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..bee0e46 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,12 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: notes +Upstream-Contact: Heiko Schaefer +Source: https://codeberg.org/openpgp/notes + +Files: book/source/diag/*.png book/source/diag/*.svg +Copyright: 2023 The "Notes on OpenPGP" project +License: CC-BY-SA-4.0 + +Files: book/source/mermaid/*.png +Copyright: 2023 The "Notes on OpenPGP" project +License: CC-BY-SA-4.0 diff --git a/.woodpecker/codespell.yml b/.woodpecker/codespell.yml new file mode 100644 index 0000000..ae9229d --- /dev/null +++ b/.woodpecker/codespell.yml @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +clone: + git: + image: woodpeckerci/plugin-git + settings: + lfs: false + +when: + branch: draft + event: + - push + - pull_request + +steps: + codespell: + image: archlinux:latest + commands: + - pacman -Sy --needed --noconfirm archlinux-keyring + - pacman -Syu --needed --noconfirm codespell make + - make -C book codespell diff --git a/.woodpecker/doc-pages.yml b/.woodpecker/doc-pages.yml index 083936b..7761478 100644 --- a/.woodpecker/doc-pages.yml +++ b/.woodpecker/doc-pages.yml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + steps: pages: image: woodpeckerci/plugin-docker-buildx diff --git a/.woodpecker/licensing.yml b/.woodpecker/licensing.yml new file mode 100644 index 0000000..ad9b14a --- /dev/null +++ b/.woodpecker/licensing.yml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +clone: + git: + image: woodpeckerci/plugin-git + settings: + lfs: false + +when: + branch: draft + event: + - push + - pull_request + +steps: + reuse: + image: fsfe/reuse diff --git a/.woodpecker/links.yml b/.woodpecker/links.yml new file mode 100644 index 0000000..01acf6b --- /dev/null +++ b/.woodpecker/links.yml @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +clone: + git: + image: woodpeckerci/plugin-git + settings: + partial: true + lfs: false + +when: + branch: draft + event: + - push + - pull_request + +steps: + link-check: + image: archlinux:latest + commands: + - pacman -Sy --needed --noconfirm archlinux-keyring + - pacman -Syu --needed --noconfirm lychee make python-myst-parser python-sphinx + - make -C book html-linkcheck diff --git a/Dockerfile b/Dockerfile index 14eb209..3941373 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + FROM sphinxdoc/sphinx AS build RUN pip install myst-parser COPY book/ /book diff --git a/LICENSES/CC-BY-SA-4.0.txt b/LICENSES/CC-BY-SA-4.0.txt new file mode 100644 index 0000000..9af251e --- /dev/null +++ b/LICENSES/CC-BY-SA-4.0.txt @@ -0,0 +1,428 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the “Licensor.” The text of the Creative Commons public +licenses is dedicated to the public domain under the CC0 Public Domain +Dedication. Except for the limited purpose of indicating that material +is shared under a Creative Commons public license or as otherwise +permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..a343ccd --- /dev/null +++ b/LICENSES/CC0-1.0.txt @@ -0,0 +1,119 @@ +Creative Commons Legal Code + +CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES +NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE +AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION +ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE +OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS +LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION +OR WORKS PROVIDED HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer exclusive +Copyright and Related Rights (defined below) upon the creator and subsequent +owner(s) (each and all, an "owner") of an original work of authorship and/or +a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later claims +of infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute +to the Commons to promote the ideal of a free culture and the further production +of creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with +a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or +her Copyright and Related Rights in the Work and the meaning and intended +legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be protected +by copyright and related or neighboring rights ("Copyright and Related Rights"). +Copyright and Related Rights include, but are not limited to, the following: + +i. the right to reproduce, adapt, distribute, perform, display, communicate, +and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + +iii. publicity and privacy rights pertaining to a person's image or likeness +depicted in a Work; + +iv. rights protecting against unfair competition in regards to a Work, subject +to the limitations in paragraph 4(a), below; + +v. rights protecting the extraction, dissemination, use and reuse of data +in a Work; + +vi. database rights (such as those arising under Directive 96/9/EC of the +European Parliament and of the Council of 11 March 1996 on the legal protection +of databases, and under any national implementation thereof, including any +amended or successor version of such directive); and + +vii. other similar, equivalent or corresponding rights throughout the world +based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time extensions), +(iii) in any current or future medium and for any number of copies, and (iv) +for any purpose whatsoever, including without limitation commercial, advertising +or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the +benefit of each member of the public at large and to the detriment of Affirmer's +heirs and successors, fully intending that such Waiver shall not be subject +to revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account Affirmer's +express Statement of Purpose. In addition, to the extent the Waiver is so +judged Affirmer hereby grants to each affected person a royalty-free, non +transferable, non sublicensable, non exclusive, irrevocable and unconditional +license to exercise Affirmer's Copyright and Related Rights in the Work (i) +in all territories worldwide, (ii) for the maximum duration provided by applicable +law or treaty (including future time extensions), (iii) in any current or +future medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional purposes +(the "License"). The License shall be deemed effective as of the date CC0 +was applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder of +the License, and in such case Affirmer hereby affirms that he or she will +not (i) exercise any of his or her remaining Copyright and Related Rights +in the Work or (ii) assert any associated claims and causes of action with +respect to the Work, in either case contrary to Affirmer's express Statement +of Purpose. + + 4. Limitations and Disclaimers. + +a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, +licensed or otherwise affected by this document. + +b. Affirmer offers the Work as-is and makes no representations or warranties +of any kind concerning the Work, express, implied, statutory or otherwise, +including without limitation warranties of title, merchantability, fitness +for a particular purpose, non infringement, or the absence of latent or other +defects, accuracy, or the present or absence of errors, whether or not discoverable, +all to the greatest extent permissible under applicable law. + +c. Affirmer disclaims responsibility for clearing rights of other persons +that may apply to the Work or any use thereof, including without limitation +any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims +responsibility for obtaining any necessary consents, permissions or other +rights required for any use of the Work. + +d. Affirmer understands and acknowledges that Creative Commons is not a party +to this document and has no duty or obligation with respect to this CC0 or +use of the Work. diff --git a/README.md b/README.md index 343a07f..8c4538a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ + + # Notes on OpenPGP The "Notes on OpenPGP" project aims to produce accessible documentation for various aspects of the OpenPGP ecosystem. diff --git a/book/.codespellrc b/book/.codespellrc new file mode 100644 index 0000000..24cc09d --- /dev/null +++ b/book/.codespellrc @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +[codespell] +skip = ./build,./source/diag/*.svg diff --git a/book/Makefile b/book/Makefile index d0c3cbf..a4c41c9 100644 --- a/book/Makefile +++ b/book/Makefile @@ -1,10 +1,16 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 +# # Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. -SPHINXOPTS ?= +CODESPELL ?= codespell +SPHINXOPTS ?= -W SPHINXBUILD ?= sphinx-build +LYCHEE ?= lychee +PRINTF ?= printf SOURCEDIR = source BUILDDIR = build @@ -12,6 +18,17 @@ BUILDDIR = build help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +html-linkcheck: clean html + @$(LYCHEE) "$(BUILDDIR)/html/"*.html + +# spell check all sources +# NOTE: diagrams are not yet spell checked, but we emit the required changes +codespell: + @$(PRINTF) "The following change suggestions are only warnings! (Please don't fix them)\n" + @$(CODESPELL) source/diag || true + @$(PRINTF) "The following change suggestions are errors!\n" + @$(CODESPELL) . + .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new diff --git a/book/make.bat b/book/make.bat deleted file mode 100644 index dc1312a..0000000 --- a/book/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/book/source/01-intro.md b/book/source/01-intro.md index 3fa5b10..a83cda4 100644 --- a/book/source/01-intro.md +++ b/book/source/01-intro.md @@ -1,3 +1,8 @@ + + # Introducing OpenPGP This documentation project seeks to introduce OpenPGP concepts and functionalities to software developers who wish to use it in their projects. @@ -14,7 +19,7 @@ With OpenPGP, you can: - [Encrypt](encryption_chapter) and [decrypt](decryption_chapter) messages - [Sign](signing_data) and [verify](verification_chapter) data -- [Issue certifications and examine statements](certifications_chapter) about keys and identities, similar to the role of a Certificate Authority in validating identities. +- [Issue certifications and examine statements](component_signatures_chapter) about keys and identities, similar to the role of a Certificate Authority in validating identities. To enable these operations, OpenPGP utilizes a set of [established cryptographic mechanisms](cyrptography_chapter). These building blocks are integrated into OpenPGP's standard, which also addresses identities and their verification. diff --git a/book/source/02-highlevel.md b/book/source/02-highlevel.md index 221ee5b..186a08e 100644 --- a/book/source/02-highlevel.md +++ b/book/source/02-highlevel.md @@ -1,3 +1,8 @@ + + # A high-level view ## Why OpenPGP? @@ -50,7 +55,7 @@ Because the GnuPG program binary is called "gpg," "GnuPG" and "gpg" are often us In 2007, the IETF published [RFC 4880](https://datatracker.ietf.org/doc/html/rfc4880), which defined version 4 of the OpenPGP standard. As of late 2023, version 4 is the most commonly used version. - +(major_implementations)= ### Major implementations of OpenPGP Today, multiple implementations of OpenPGP play important roles: diff --git a/book/source/03-cryptography.md b/book/source/03-cryptography.md index f79051f..b85d982 100644 --- a/book/source/03-cryptography.md +++ b/book/source/03-cryptography.md @@ -1,43 +1,64 @@ + + (cyrptography_chapter)= # Cryptographic concepts and terms -```{admonition} VISUAL -:class: warning +## Cryptographic hash functions -- Introduce visualizations for cryptographic primitives -- Show example visualizations for operations? (encrypt/decrypt and signing/verification - only if we're going to reuse the visual primitives later) -``` +[Cryptographic hash functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) take data strings of any length (like a text message or file) and output a fixed-size code, often called a "hash" or "digest." This hash acts like a unique identifier for the original data. -## (Cryptographic) hash functions +Here are two important properties of cryptographic hash functions: -[(Cryptographic) hash functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) map binary data of arbitrary length to a fixed size "hash" (hashes are also sometimes called "digests"). +- ["Pre-image resistance"](https://en.wikipedia.org/wiki/Preimage_attack): Given a hash value, it should be very difficult to determine the original data it represents. +- ["Collision resistance"](https://en.wikipedia.org/wiki/Collision_resistance): It should be very difficult to find two distinct pieces of data that map to the same hash value. -Hash functions are used in cryptography to produce shorthand "placeholders" for data. Two properties of cryptographic hash functions are particularly important: +## Message authentication codes -- ["Pre-image resistance"](https://en.wikipedia.org/wiki/Preimage_attack): Given a hash value, it should be hard to find a message that maps to that hash value. -- ["Collision resistance"](https://en.wikipedia.org/wiki/Collision_resistance): It should be hard to find two messages that map to the same hash value. +A [message authentication code](https://en.wikipedia.org/wiki/Message_authentication_code) (MAC), also known as an authentication tag, is a small piece of information used to verify the integrity and authenticity of a message. + +It is derived from the original message using a (symmetric) secret key. The recipient of a message containing a MAC, who is also in possession of the secret key, can verify that the message has not been altered. + +[HMAC](https://en.wikipedia.org/wiki/HMAC) is a type of MAC that relies on a hash function. It is used in the OpenPGP protocol. + +### Key derivation functions + +A hash function can also be used to create a [key derivation function](https://en.wikipedia.org/wiki/Key_derivation_function) (KDF). +One application of KDFs is to generate symmetric key material from a password by iteratively passing it through a hash function. + +A notable KDF for the OpenPGP specification is the [HKDF](https://en.wikipedia.org/wiki/HKDF), which is a key derivation function based on the HMAC. + +For detailed information on KDFs and their role in the OpenPGP protocol, see the [encrypted secrets](encrypted_secrets) chapter and the [SEIPDv2](SEIPDv2) section of the encryption chapter. ## Symmetric-key cryptography -[Symmetric-key cryptography](https://en.wikipedia.org/wiki/Symmetric-key_algorithm) uses the same cryptographic key for both encryption and decryption. Symmetric-key cryptographic systems support *encryption/decryption* operations. +[Symmetric-key cryptography](https://en.wikipedia.org/wiki/Symmetric-key_algorithm) uses the same cryptographic key for both encryption and decryption, unlike asymmetric cryptography where a pair of keys is used: a public key for encryption and a corresponding private key for decryption. Symmetric-key cryptographic systems support *encryption/decryption* operations. Participants in symmetric-key operations need to exchange the shared secret over a secure channel. -```{admonition} VISUAL -:class: warning - -- visualization? (maybe a black key icon, following wikipedia's example?) +```{figure} diag/symmetric_key.png +--- +--- +A symmetric cryptographic key (which acts as a shared secret) ``` ### Benefits and downsides -Symmetric-key cryptography has major benefits: it is much faster than public-key cryptography (see below). Also, most current symmetric cryptographic algorithms are considered quantum-resistant[^postquantum]. +Symmetric-key cryptography has major benefits: It is much faster than public-key cryptography (see below). Also, most current symmetric cryptographic algorithms are considered quantum-resistant[^postquantum]. [^postquantum]: Daniel J. Bernstein (2009). ["Introduction to post-quantum cryptography" (PDF)](http://www.pqcrypto.org/www.springer.com/cda/content/document/cda_downloaddocument/9783540887010-c1.pdf) states that: "many important classes of cryptographic systems", including secret-key cryptographic mechanisms like AES "[..] are believed to resist classical computers and quantum computers." (pages 1, 2). +```{admonition} TODO +:class: warning + +I am not convinced that this information is helpful but, if it remains, perhaps we need this additional statement: "That is, symmetric-key cryptographic mechanisms are currently considered to be resilient against known computer threats, providing a measure of assurance in the evolving landscape of cryptography and quantum computing." +``` + However, exchanging the required shared secret is a problem that needs to be solved separately. -[Hybrid cryptosystems](hybrid_cryptosystems) (see below) are one common approach to leverage the benefits of symmetric-key cryptography, while handling the shared secret with a separate mechanism (using public-key cryptography). +[Hybrid cryptosystems](hybrid_cryptosystems) combine the advantages of symmetric-key cryptography with a separate mechanism for managing the shared secret, using public-key cryptography. ### Symmetric-key cryptography in OpenPGP @@ -45,85 +66,85 @@ Symmetric-key cryptography is used in OpenPGP in three contexts: - most prominently, as part of a hybrid cryptosystem to encrypt and decrypt data, - to encrypt [password-protected private key material](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-key-encryption), and -- for [password-protected data encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-symmetric-key-encrypted-ses) (a less commonly used feature of the standard). +- for [password-protected data encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-symmetric-key-encrypted-ses), a less commonly used feature of the standard. Where symmetric keys are used in OpenPGP for data encryption, they are called either "message keys" or "session keys[^sessionkey]." -[^sessionkey]: In OpenPGP version 6, when using the ["Version 2 Symmetrically Encrypted Integrity Protected Data Packet Format"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-2-symmetrically-enc), a "message key" is derived from a "session key". Previously (up to OpenPGP version 4, and in version 6 when using ["Version 1 Symmetrically Encrypted Integrity Protected Data Packet Format"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-1-symmetrically-enc)), the "session key" was used directly as a symmetric encryption key. +[^sessionkey]: In OpenPGP version 6, the ["Version 2 Symmetrically Encrypted Integrity Protected Data Packet Format"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-2-symmetrically-enc) requires that a "message key" is derived from a "session key." In contrast, up to OpenPGP version 4, and in version 6 when using ["Version 1 Symmetrically Encrypted Integrity Protected Data Packet Format"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-1-symmetrically-enc), the "session key" was used directly as a symmetric encryption key. ### Authenticated encryption with associated data (AEAD) -[Authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) is a class of cryptographic schemes that gives additional guarantees besides confidentiality. +[Authenticated encryption](https://en.wikipedia.org/wiki/Authenticated_encryption) offers more than just confidentiality; it ensures data integrity too. -In OpenPGP version 6, AEAD was introduced as a successor to the MDC[^MDC] mechanism. AEAD is a common mechanism to solve the problem of "malleability": In past versions of the OpenPGP protocol, some malicious changes to ciphertext were undetectable. AEAD protects against undetected changes of ciphertext. +In OpenPGP version 6, AEAD replaced the MDC[^MDC] mechanism to address malleability. In earlier OpenPGP versions, malicious alterations to ciphertext might go unnoticed. AEAD guards against such undetected changes. -[^MDC]: In OpenPGP version 4, a mechanism called MDC (Modification Detection Code) was introduced to serve a comparable purpose as AEAD. While MDC is a non-standard mechanism, as of this writing, there are no known attacks against the scheme. +[^MDC]: OpenPGP version 4 introduced a mechanism called MDC (Modification Detection Code), which fulfills a comparable purpose as AEAD in safeguarding message integrity. MDC is a non-standard mechanism, but no known attacks have compromised this scheme as of this document's last update. -Protecting against malleability counters a variation of the EFAIL[^efail] attack. +By addressing the malleability problem, AEAD also counters a variation of the EFAIL[^efail] attack. -[^efail]: A variation of the [EFAIL](https://en.wikipedia.org/wiki/EFAIL) attack can be prevented by both the MDC and AEAD mechanisms. Also see ["No, PGP is not broken, not even with the Efail vulnerabilities"](https://proton.me/blog/pgp-vulnerability-efail), especially the section "Malleability Gadget Exfiltration Channel Attack". +[^efail]: A variation of the [EFAIL](https://en.wikipedia.org/wiki/EFAIL) attack can be prevented by both the MDC and AEAD mechanisms. Also see ["No, PGP is not broken, not even with the Efail vulnerabilities,"](https://proton.me/blog/pgp-vulnerability-efail) especially the section "Malleability Gadget Exfiltration Channel Attack." +## Public-key (asymmetric) cryptography -## Public-key, or asymmetric cryptography +[Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) uses asymmetric pairs of related keys. Each pair consists of a public key and a private key. These systems support encryption, decryption, and digital signature operations. -[Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) systems use asymmetric pairs of related keys. Public-key cryptographic systems support *encryption/decryption* as well as *digital signature* operations. - -Unlike symmetric cryptography, public-key cryptography doesn't require participants to pre-arrange a shared secret. Instead, with public-key cryptography, the public parts of the key material can be shared openly and then used for cryptographic operations. +Unlike symmetric cryptography, participants are not required to pre-arrange a shared secret. In public-key cryptography, the public key material is shared openly for certain cryptographic operations, such as encryption and signature creation, while the private key, kept confidential, is used for operations like decryption and signature verification. (asymmetric_key_pair)= ### Asymmetric cryptographic key pairs -In many places, we'll deal with asymmetric cryptographic key pairs: +Throughout this document, we will frequently reference asymmetric cryptographic key pairs: -```{figure} diag/cryptographic_keypair.png +```{figure} diag/asymmetric_keypair.png --- --- An asymmetric cryptographic key pair ``` -An asymmetric cryptographic key pair consists of a public and a private part. In this document, we'll show the public part of a key pair in green, and the private part in red. +Each key pair comprises two parts: the public key and the private key. For ease of identification, we will depict the public key in green and the private key in red throughout this document. -Note that in many contexts, only the public part is present (more on that later): +It's important to note that in many scenarios, only the public key is exposed or used (we will expand on these situations in subsequent sections): -```{figure} diag/keypair_pub.png +```{figure} diag/public_key.png --- --- -Only the public part of an asymmetric key pair +The public parts of an asymmetric key pair ``` -### Public-key cryptography in OpenPGP +### Usage and terminology in OpenPGP -OpenPGP makes heavy use of public-key cryptography, both for encryption and signing operations. +OpenPGP extensively uses public-key cryptography for encryption and digital signing operations. ```{admonition} Terminology :class: note -For historical reasons, the OpenPGP RFC and other documentation often use the non-standard term "secret key" instead of the more common "private key." +OpenPGP documentation, including the foundational RFC, opts for the term "secret key" over the more widely accepted "private key." As a result, in the RFC, you'll encounter the "public/secret key" pairing more frequently than "public/private key." This terminology reflects historical developments in the OpenPGP community, not a difference in technology. -So in OpenPGP, the pair of terms "public/secret key" is sometimes used instead of the more common "public/private key." +While "secret key" (as used in the OpenPGP RFC) and "private key" serve the same purpose in cryptographic operations, this document will use the more common "public/private" terminology for clarity and consistency with broader cryptographic discussions. ``` ### Cryptographic digital signatures -[Digital signatures](https://en.wikipedia.org/wiki/Digital_signature) are a mechanism that is based on asymmetric cryptography. With this mechanism, one actor can make a signature over a digital message, and another actor can check the validity of that signature. +[Digital signatures](https://en.wikipedia.org/wiki/Digital_signature) are a fundamental mechanism of asymmetric cryptography, providing secure, mathematical means to validate the authenticity, integrity, and origin of digital messages and documents. -The signer uses digital signatures to make statements about the message. Third parties can then inspect these statements. +In OpenPGP, digital signatures have diverse applications, extending beyond mere validation of a message's origin. They can signify various intents, including certification, consent, acknowledgment, or even revocation by the signer. The multifaceted nature of "statements" conveyed through digital signatures in cryptographic protocols is wide-ranging but crucial, allowing third parties to inspect/evaluate these statements for authenticity and intended purpose. -```{admonition} VISUAL -:class: warning +Digital signatures in OpenPGP are used in two primary contexts: -- add visualization showing: message + private key + sign = signature -> message + signature + public key + verify = ok? -``` - -In OpenPGP, digital signatures are used in two different contexts: - -- [Certification statements](certifications_chapter) -- [Signatures over data](signing_data) +- [Certification statements](component_signatures_chapter) +- [Data signatures](signing_data) (hybrid_cryptosystems)= ## Hybrid cryptosystems -[Hybrid cryptosystems](https://en.wikipedia.org/wiki/Hybrid_cryptosystem) combine two cryptosystems and make use of their respective advantages: +OpenPGP uses a hybrid cryptosystem. [Hybrid cryptosystems](https://en.wikipedia.org/wiki/Hybrid_cryptosystem) combine the use of symmetric and asymmetric (public-key) cryptography to capitalize on the strengths of each, namely symmetric cryptography's speed and efficiency and public-key cryptography's mechanism for secure key exchange. -- A public-key cryptosystem is used to safely handle shared secrets over insecure channels (in OpenPGP: so-called "session keys") -- A symmetric-key cryptosystem is used to efficiently encrypt and decrypt long messages (using an OpenPGP "session key" as the shared secret) +```{admonition} TODO +:class: warning + +Move this to the chapter that details it: + +Within OpenPGP's hybrid system, so-called "session keys" are central. They are generated uniquely for each session and are instrumental in both encrypting and decrypting the actual message content, using the efficiency of symmetric-key cryptography. + +Using asymmetric (public-key) cryptography, the session keys are also encrypted. This ensures that only the intended recipient, the holder of the corresponding private key, can decrypt and gain access to the session key. With the decrypted session key, they can then use the session key to decrypt the actual message. +``` \ No newline at end of file diff --git a/book/source/04-certificates.md b/book/source/04-certificates.md index 5cac7d8..2cd8491 100644 --- a/book/source/04-certificates.md +++ b/book/source/04-certificates.md @@ -1,3 +1,8 @@ + + (certificates_chapter)= # Certificates @@ -183,7 +188,7 @@ Currently, the OpenPGP standard prescribes only one format to be stored in user ## Linking the components -To form an OpenPGP certificate, individual components are interconnected by the certificate holder using their OpenPGP software. Within OpenPGP, this process is termed "binding," as in "a subkey is bound to the primary key." These bindings are realized using cryptographic signatures. An in-depth discussion of this topic can be found in {ref}`certifications_chapter`). +To form an OpenPGP certificate, individual components are interconnected by the certificate holder using their OpenPGP software. Within OpenPGP, this process is termed "binding," as in "a subkey is bound to the primary key." These bindings are realized using cryptographic signatures. An in-depth discussion of this topic can be found in {ref}`component_signatures_chapter`). In very abstract terms, the primary key of a certificate acts as a root of trust or "certification authority." It is responsible for: diff --git a/book/source/05-private.md b/book/source/05-private.md index 9820dec..49ac43c 100644 --- a/book/source/05-private.md +++ b/book/source/05-private.md @@ -1,5 +1,12 @@ + + (private_key_chapter)= -# OpenPGP private keys +# Private key material in OpenPGP + +This chapter discusses the handling of private key material, in OpenPGP. Private key material is associated with component keys that are parts of [OpenPGP certificates](certificates_chapter). For a discussion of packet structure internals, see the chapter {ref}`zoom_private` Historically, terminology around OpenPGP certificates and keys has often been used inconsistently. The pair of terms "OpenPGP public key" and "OpenPGP private/secret keys" were commonly used (while the shorthand "OpenPGP key" can refer to both, depending on context). @@ -9,34 +16,41 @@ In this document, we use the term *OpenPGP certificate* to refer "OpenPGP public This chapter is about the counterpart to the public material in certificates: Here, we discuss the handling of *private key material* in OpenPGP. -In this text, we treat the private key material as logically separate from the OpenPGP certificate. Operations that use the private key material are typically handled by a separate subsystem. We think it is useful to think about OpenPGP certificates on one hand, and the associated private key material, on the other, as two related elements, which are usually handled separately[^pkcs11]: +In this text, we treat the private key material as logically separate from the OpenPGP certificate. Operations that use the private key material are typically handled by a separate subsystem. It is useful to think about OpenPGP certificates on one hand, and the associated private key material, on the other, as two related elements, which are usually handled separately[^pkcs11]: -```{admonition} VISUAL -:class: warning -- OpenPGP certificate side-by-side with the associated, loose private key material +```{figure} diag/OpenPGPCert_with_privatekeystore.png + +An OpenPGP certificate, with the associated private key material handled by a key store subsystem. ``` [^pkcs11]: This kind of distinction between certificates (which combine public key material and identity information) on the one hand, and private key material on the other, is also applied in the data model of [PKCS #11](https://en.wikipedia.org/wiki/PKCS_11) cryptographic systems. -However, there is one exception. "OpenPGP private keys" are sometimes handled in a format that combines the certificate and the private key data: [*Transferable secret keys (TSK)*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-transferable-secret-keys). +However, there is one exception. Raw cryptographic private key material is sometimes embedded in an OpenPGP framing format that additionally contains the certificate: [*Transferable secret keys (TSK)*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-transferable-secret-keys). + +```{admonition} Terminology +:class: note + +Transferable secret keys are sometimes colloquially referred to as "OpenPGP private keys". +``` ## Transferable secret keys -Sometimes users handle "OpenPGP private keys" in the form of *transferable secret keys* (TSK). That is: a serialized format that combines the OpenPGP certificate data with the connected private key material, stored in a single file. +Sometimes users handle OpenPGP certificates combined with private key material in the form of *transferable secret keys* (TSK). Transferable secret keys are a serialized format that combines the OpenPGP certificate data with the connected private key material, stored in a single file. -```{admonition} VISUAL -:class: warning +```{figure} diag/TSK.png -- OpenPGP certificate with integrated private key material, as TSK +OpenPGP certificate with integrated private key material, as a TSK ``` The TSK format can be useful for backups of OpenPGP key material, or to move a key to a different computer[^gpg-tsk]. [^gpg-tsk]: For example, with GnuPG, an OpenPGP key can be exported in (armored) TSK format like this: `gpg --export-secret-key --armor ` +See the chapter {ref}`zoom_private` for insights into the packet structure of a TSK. + (encrypted_secrets)= -## Protecting secret key material with a passphrase (using S2K) +## Protecting private key material with a passphrase (using S2K) In OpenPGP format, private key material can be optionally protected with a [passphrase](https://en.wikipedia.org/wiki/Passphrase). This mechanism applies symmetric encryption to the private key data in component keys. @@ -46,13 +60,16 @@ Using a passphrase can be useful when a third party can obtain a copy of the Ope OpenPGP defines a mechanism called [string-to-key (S2K)](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-string-to-key-s2k-specifier) that is used to derive (high-entropy) symmetric encryption keys from (lower-entropy) passphrases, using a [key derivation function (KDF)](https://en.wikipedia.org/wiki/Key_derivation_function). -```{admonition} VISUAL -:class: warning +```{figure} diag/passphrase_using_S2K.png -- passphrase --(S2k mechanism)--> symmetric encryption key +Transforming a passphrase into a symmetric key ``` -Encryption of private key material can be configured independently for each component key. Component keys that are associated with the same certificate can use different mechanisms for passphrase protection, and/or different passphrases. +The private key material for individual component keys of one certificate can be encrypted with different mechanisms, and/or using different passphrases. + +However, this is not customarily done. Usually, when creating a certificate, the user's software will use the same encryption mechanism and passphrase for all component keys (to limit complexity). + +However, when adding new subkeys to a certificate at a later date, the user might choose to use a different passphrase. Or the user's software may choose a different encryption mechanism, e.g. based on updated best practices. ### S2K mechanisms for symmetric key generation @@ -68,14 +85,38 @@ Different mechanisms are specified [for the encryption of the secret key data](h ## Private key operations -The core of private key operations doesn't require access to the whole certificate. A private key subsystem only needs to handle the cryptographic key material. +The core of private key operations doesn't require access to the whole certificate. + +Designs of private key subsystems in the OpenPGP space differ: + +- Some designs perform the primitive cryptographic operations in a separate backend, only using the cryptographic key material itself. This type of design matches well with general purpose hardware cryptographic devices (such as TPMs). +- In other designs, the OpenPGP private key subsystem requires the additional metadata that is stored in the component key (the key creation time, for all keys, and in the case of keys that use ECDH algorithms: the KDF parameters). + +Either way: at most, a private key subsystem should need access to individual component keys and the associated private key material. + +```{note} + +Keeping a copy of the full certificate information in the private key subsystem can cause "split brain" problems. E.g.: expiration times could then differ between different subsystems, when they keep different copies of the certificate information. + +(Thunderbird users currently suffer from such issues, I think) +``` ### OpenPGP card for private keys -[OpenPGP card](https://en.wikipedia.org/wiki/OpenPGP_card) devices are a type of hardware security device. They are one popular way to handle OpenPGP private key material. These devices do not store the full OpenPGP certificate. +[OpenPGP card](https://en.wikipedia.org/wiki/OpenPGP_card) devices are a type of hardware security device. They are one popular way to handle OpenPGP private key material. + +OpenPGP card devices implement an open specification: [Functional Specification of the OpenPGP application on ISO Smart Card Operating Systems, Version 3.4.1](https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.1.pdf). Multiple vendors produce devices that implement this specification, and there are a number of Free Software implementations (some of which can even be run on open hardware designs). + +Effectively, the OpenPGP card specification outlines one model for an OpenPGP private key subsystem: + +OpenPGP card devices do not store the full OpenPGP certificate. Instead, they have three "key slots": one each for signing, decryption and authentication. Each key slots stores the component key data and the associated cryptographic private key material[^missing-ecdh]. In addition, for each key slot, the OpenPGP fingerprint for the contained component key is explicitly stored on the card (note that storing the fingerprint on the card is different from how OpenPGP key data is usually handled: normally, fingerprints are not explicitly stored, but calculated on the fly from the component key data). + +[^missing-ecdh]: In the case of ECDH keys, the KDF parameters (hash function ID and a symmetric encryption algorithm ID) are not stored on the OpenPGP card. This is considered a flaw in the OpenPGP card specification. These missing parameters can be handled in two ways, by OpenPGP software running on the host computer: Either by consulting a copy of the component key (e.g. by inspecting a copy of the certificate), or by deducing the missing KDF parameters from the OpenPGP fingerprint that is stored on the card. ## Advanced topics ### TSKs: Best practices S2K + S2K migration? ### The KOpenPGP attack + +See [https://www.kopenpgp.com/](https://www.kopenpgp.com/) diff --git a/book/source/06-certifications.md b/book/source/06-certifications.md deleted file mode 100644 index 6b12dde..0000000 --- a/book/source/06-certifications.md +++ /dev/null @@ -1,90 +0,0 @@ -(certifications_chapter)= - -# Certification signatures - -Signatures make up the magic of OpenPGP. -They act as the syntax that allows forming and interpreting complex statements about data and identities. -Without signatures there would only be loose keys, impossible to associate with their owner. -Signatures are the glue that allows for keys, subkeys and identities to be assembled into hierarchical certificates and for messages to gain authenticity. - -```{admonition} TODO -:class: warning - - - Purpose of a signature - - Meaning of different signature types, nuances of subpackets - - Can we have a "catalogue" of statements a user might want to make, mapping these to archetypical signatures? - - Revocation; Hard vs. Soft -``` - -## Terminology - -The term *signature* can have multiple meanings in the context of the OpenPGP specification. -Cryptographic keys create raw signatures which are byte sequences calculated according to some signature scheme. -OpenPGP packs these raw signatures up into OpenPGP signature packets, which carry additional information in the form of signature subpackets. -For the purpose of this document, the term signature will refer to an OpenPGP signature packet (tag 2). - -OpenPGP signatures can be separated into *data signatures* and *certifications*. -A data signature serves the purpose to cryptographically guarantee the authenticity (and implicitly also the integrity) of a message, e.g. an email or a file, while a certification is used to attach metadata or subkeys to a certificate. -Data signatures are always calculated by keys carrying the **S**igning key flag, while certifications require keys carrying the **C**ertify Others key flag (with the exception of so called Primary Key Binding Signatures). -Different types of signatures are distinguished by a signature type code and are calculated in different ways. -Signatures can either be distributed standalone as *detached* signatures, or can be inlined with OpenPGP data, such as an OpenPGP message or a key or certificate. - -Data signatures (type 0x00 and 0x01) are created by hashing the message content and calculating a cryptographic signature over the hash. -The result is packed up into an OpenPGP signature packet, which can either be included in the OpenPGP message (TODO: See section about forming messages, cleartext signature framework), or distributed separately as a so called *detached* signature. -Data signatures are always calculated using a **S**igning key. - -A certification made by a key over components of the same certificate is referred to as a *self-certification*. -A typical use-case for a self-certification is to attach a user ID, such as a name and email address to a certificate. -This is done by calculating the signature over the user ID and the public primary key. -The resulting user ID certification (typically type 0x13, potentially type 0x10-0x12) can then be inserted into the certificate, right after the user ID packet. - -Other examples for self-signatures are binding signatures for subkeys. -In order to add an OpenPGP subkey to a certificate, a subkey binding signature is calculated over the public primary key, followed by the public subkey. -The resulting subkey binding signature (type 0x18) can then be inserted into the certificate right after the subkey. -If the subkey itself is intended to be used as a **S**igning key, an extra step is required. -To prevent an attacker from being able to "adopt" a victims signing subkey and then being able to claim to be the origin of signatures in fact made by victim, subkey binding signatures for signing subkeys need to include an embedded "back signature" (formally known as primary key binding signature) made by the signing key itself. - -Certifications over user IDs can also be used to certify certificates of third-parties. -If Alice is certain that `Bob Baker ` controls the key 0xB0B, she can create a user ID certification signature for that identity and send it to Bob. -Bob can then add this signature to his certificate. -TODO: More WoT. - -Another important category of signatures are revocations. -A revocation is used to retract the statement formed by a prior signature. -A subkey revocation signature revokes a prior subkey binding signature, while a certification revocation revokes a certification signature. -Typical use-cases for revocations are marking certificates or individual subkeys as unusable, or marking user IDs as no longer used. - -## Signature Subpackets - -A cryptographic signature alone is often not expressive enough to fulfil certain use-cases. -For this reason, the OpenPGP protocol introduced signature subpackets with rfc4880. -These are well-defined data structures that can be placed as subelements into signature packets, which give additional context and meaning to a signature. -Typical examples are the issuer fingerprint subpacket, which contains the fingerprint of the issuer key, or the key flags subpacket which states, what purpose a component key is intended for. - -Signature subpackets can reside in two different areas of a signature packet. -Subpackets in the *hashed area* are incorporated in the digest calculation that is done during signature calculation and are therefore covered by the cryptographic signature. -Hashed subpackets are *authenticated*. -If a subpacket is placed in the *unhashed area* instead, it is not included in the signature calculation procedure. -The unhashed area can be used to retroactively add, change or remove subpackets from a signature without invalidating it. - -Due to the fact that the unhashed area doesn't provide any cryptographic guarantees, it is only intended for advisory packets, or packets that self-authenticate (e.g. issuer key ID / issuer fingerprint subpackets, whose "correctness" can be proven by successfully verifying the signature using the referenced issuer key). -In most cases, signature subpackets are simply added into the hashed area. - -Since the hashed and unhashed areas of a signature are just lists of subpackets, in principle they allow duplicates of the same subpacket, which might lead to conflicts. -Therefore, packets in the hashed area take precendence over the unhashed area. -However, there may still be conflicts between packets in the same area, e.g. two conflicting expiration dates, etc. -The specification recommends that implementations favor the last occurence of a conflicting packet. - -In some cases, duplicate packets with conflicting content even make sense, e.g. if a signature was made by a version 6 issuer key whose key material was migrated from an older OpenPGP version such as v4. -In this case, the v4 key could be used to validate the v6 signature, but since the fingerprint and key ID calculation scheme was changed between v4 and v6, these identifiers would differ. -Therefore, the signature could contain two sets of issuer fingerprint and isuer key ID subpackets with conflicting, but correct values. - -```{admonition} TODO -:class: warning - -- Key Flags -- Preferences -- Embedded Signature (back sig) -- Trust Signatures (amount, depth) -- Direct key signatures -``` diff --git a/book/source/06-signatures.md b/book/source/06-signatures.md new file mode 100644 index 0000000..a830a9b --- /dev/null +++ b/book/source/06-signatures.md @@ -0,0 +1,117 @@ + + +# OpenPGP Signatures + +Signatures make up the magic of OpenPGP. They act as the syntax that allows forming and interpreting rich statements about certificates and their components, as well as data. + +Without signatures, there would only be loose keys, impossible to associate with a certificate, or their owner. Signatures are the glue that allows for components (component keys and identity components) to be assembled into hierarchical certificates, and for messages to gain authenticity. + +## Terminology + +The term *signature* can have multiple meanings in the context of OpenPGP: + +- Cryptographic keys create raw signatures which are byte sequences calculated according to some signature scheme. +- [*OpenPGP signature packets*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-packet-type-id-2), which combine a *type* setting, additional metadata, and a raw cryptographic signature. + + +```{figure} diag/types_of_signatures.png + +Two meanings of the term "signature" in OpenPGP +``` + +For the purpose of this document, the term signature will refer to OpenPGP signature packets. + +(signature_types)= +## Types of signatures in OpenPGP + +The OpenPGP standard defines a set of [Signature Types](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-types), each identified by a numerical *signature type ID*. Signature types define the intent of a signature, and how it needs to be interpreted. + +```{figure} mermaid/06-terminology.png + +An overview of signature types in OpenPGP +``` + +Most OpenPGP signature types can be classified as either: + +- *Signatures over data*, or +- *Signatures on components* (that is: signatures that apply to component keys or identity components). + +In this chapter, we discuss the general principles of OpenPGP signatures, which apply to all types of OpenPGP signatures. + +For more detail about specific types of signatures, see the chapters {ref}`signing_data` and {ref}`component_signatures_chapter`, respectively. + +## Structure of an OpenPGP signature + +As outlined above, an OpenPGP signature is a composite data structure, which combines: + +- A *signature type ID* (see above), which specifies the intended meaning of the signature, +- Metadata (which is variable and depends in part on the type ID), + - Most of this metadata is encoded as so-called "subpackets," see {ref}`signature_subpackets`, +- A raw cryptographic signature. + + +```{admonition} VISUAL +:class: warning + +show a version of our "yellow tag-thing with sig-circle" visual? +``` + +The cryptographic signature is calculated by its issuer. It certifies a hash digest, which in turn combines a set of input data. The exact input data depends on the signature type. Roughly: the hash digest is over the elements that the OpenPGP signature makes a statement about, combined with the metadata in the OpenPGP signature packet itself. More on this later. + +(signature_subpackets)= +## Signature subpackets + +Just a cryptographic signature, combined with a signature type identifier, is often not sufficiently expressive. For this reason, the OpenPGP protocol introduced signature subpackets (in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440)). + +Subpackets are well-defined data structures that can be placed into signature packets as subelements. They give additional context and meaning to a signature. Subpackets encode data in a key-value format. All possible keys are defined in the RFC as [subpacket type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-subpacket-types-r), and the value format (and meaning) are defined in the RFC for each subpacket type ID. + +Typical examples are: +- the [*issuer fingerprint*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#issuer-fingerprint-subpacket) subpacket, which contains the fingerprint of the issuer key, or +- the [*key flags*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) subpacket which defines what purpose a component key is used for, in a certificate. + +Signature subpackets can reside in two different areas of a signature packet: + +- Subpackets in the *hashed area* are incorporated in the digest calculation that is done during signature calculation and are therefore covered by the cryptographic signature. In other words; hashed subpackets are *authenticated*. +- If a subpacket is placed in the *unhashed area* instead, it is not included in the signature calculation procedure and is therefore not protected against tampering. The unhashed area can be used to retroactively add, change or remove subpackets from a signature without invalidating it. Since the unhashed area doesn't provide any cryptographic guarantees, it is only intended for advisory packets, or packets that self-authenticate (e.g. the issuer fingerprint subpacket, whose "correctness" can be proven by successfully verifying the signature using the referenced issuer key). + +In most cases, signature subpackets are stored in the hashed area. + +### Criticality of subpackets + +Each signature subpacket has a flag that indicates whether the subpacket is *critical*. + +Since different OpenPGP implementations might support subsets of the standard, it would be fatal if, for example, an implementation did not understand the concept of signature expiration. Such an implementation would potentially accept an already expired signature. +By marking the expiration date subpacket as critical, the user can indicate that implementations that do not understand this type of subpacket are supposed to reject the signature as invalid. + +RFC Sections [5.2.3.11](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-creation-time) - [5.2.3.36](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr) give guidance on which subpackets are usually marked as critical. + +## Advanced topics + +### Notation signature subpackets + +[Notations](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#notation-data) are a signature subpacket type that can be used to effectively extend the otherwise limited set of signature subpacket types with user-defined notations. An issuer can use notations to add name-value data to an OpenPGP signature. + +Notation names are UTF-8 encoded strings. They may reside in the "user namespace," which means a notation *tag* (in UTF-8 string format) followed by a DNS domain name. + +#### Use of notations by Keyoxide + +Notations have, for example, been used for the popular decentralized identity verification service [Keyoxide](https://keyoxide.org/). Keyoxide uses notations in the `ariadne.id` namespace. See the [Keyoxide documentation](https://docs.keyoxide.org/wiki/ariadne-identity/) for more details. + +### "Negotiating" signature hash algorithm based on recipients preference subpackets + +```{admonition} TODO +:class: warning + +investigate, discuss: GnuPG uses preference packets for the User ID that was addressed while sequoia completely omits User ID preferences and either uses Direct Key Sigs or (I think) primary User ID. +``` + +### Explore viability of having multiple signatures, e.g. v4+v6? + +```{admonition} TODO +:class: warning + +C-R 5.2. says: An implementation MUST generate a version 6 signature when signing with a version 6 key. An implementation MUST generate a version 4 signature when signing with a version 4 key. +``` diff --git a/book/source/07-signing_data.md b/book/source/07-signing_data.md index 7ec8512..77d0642 100644 --- a/book/source/07-signing_data.md +++ b/book/source/07-signing_data.md @@ -1,13 +1,77 @@ + + (signing_data)= # Signatures over data -```{admonition} TODO -:class: warning +A data signature guarantees the authenticity (and implicitly also the integrity) of a message, e.g., an email or a file. -Add content, including: +Note that signatures over data are different from {ref}`component_signatures_chapter`, which are used to attach metadata or subkeys to a certificate. -- Signature of a binary document +One major use case for OpenPGP is to create signatures for software packages or emails. These are examples for signatures over data, with OpenPGP. -- Signature of a canonical text document - - "The signature is calculated over the text data with its line endings converted to ``" -``` +When signing data, OpenPGP offers the advantage that it comes with mechanisms for strong authentication, based on bindings between certificates and identities, and the option to certify those bindings. + +Other signing solutions, like [signify](https://flak.tedunangst.com/post/signify), typically only offer a solution for pure signing, without offering +a mechanism for authentication. + +## Signature types + +Two OpenPGP [signature types](signature_types) apply to data signatures: + +- Signature of a binary document (*Binary Signature*, type ID `0x00`): a universal signature type for binary data. This signature type is typically used for files or data streams. +Binary signatures are calculated over the data "as is", without performing any transformations. +- Signature of a canonical text document (*Text Signature*, type ID `0x01`): used for textual data, such as email bodies. When calculating a text signature, the data is first normalized by converting line endings into a canonical form (``). This normalization mitigates issues caused by platform-specific default text encodings. + (This can be useful for detached signatures, when the message file may get re-encoded between signature generation and validation) + +Data signatures are always calculated by a component key that carries the *signing* key flag. + +Data signatures are created by hashing the message content and calculating a cryptographic signature over the hash. +The resulting cryptographic signature is stored in an OpenPGP signature packet, which can be used in different ways: + +## Forms of OpenPGP data signatures + +OpenPGP signatures over data can be generated and distributed in three forms[^sign-modes-gpg]: + +- *Detached*: The signature is a standalone artifact, separate from the signed data. +- *Inline*: The original data and the signature over the data are stored in an OpenPGP container. +- *Cleartext signature*: A method to sign text while leaving the original message in a human-readable format. + +[^sign-modes-gpg]: These signature forms correspond with GnuPG's `--detach-sign`, `--sign` and `--clear-sign` modes. + +### Detached signatures + +A detached signature is produced by calculating an OpenPGP signature over a piece of data. +The resulting OpenPGP signature packet can then be distributed alongside or independent of the original data. + +This method is especially useful for signing software releases and other files that must not be modified by the signing process. + +### Inline signatures + +This method is usually used with signed and/or encrypted emails. + +Most clients that support OpenPGP for encrypted and/or signed messages make use of inline-signatures. +To produce a signature, the entirety of the data needs to be processed by the producer. This has the consequence that an application that efficiently emits signed data can only append the signature at the end of the data stream. +On the other hand, an application that needs to efficiently verify signed data needs to know the signer's public key and used hash algorithm before processing the data. +To solve this issue, so-called One-Pass-Signature packets are prefixed to the signed data. Those are small packets containing the fingerprint of the signing key, as well as the used hash algorithm. This is all the information a receiving application needs to know to initiate the verification process. + +To produce an inline-signed message, the original data is first wrapped in a Literal Data packet, which is prefixed with one or more One-Pass-Signature packets, and affixed with the corresponding signature packets. +The verifying application can read the One-Pass-Signature packets and initiate the verification process. +The literal data can then be processed, such that the signatures at the end of the message can be verified in *one pass*. + +TODO: explain nesting of OPSs. + +### Cleartext signatures + +The *Cleartext Signature Framework* (CSF) is a mechanism that combines two goals: + +- It leaves the message in clear text format, so that it can be viewed directly by a human in a program that knows nothing about OpenPGP. +- But also adds an OpenPGP signature that allows verification of that message by users whose software supports OpenPGP. + +TODO: explain text transforms for cleartext signatures (LF->CRLF etc) + +#### Pitfalls + +The RFC points out a number of [pitfalls of cleartext signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-issues-with-the-cleartext-s), and advises that in many cases, the inline and detached signature forms are preferable. diff --git a/book/source/08-signature_internals.md b/book/source/08-signature_internals.md deleted file mode 100644 index 0e3bc53..0000000 --- a/book/source/08-signature_internals.md +++ /dev/null @@ -1,13 +0,0 @@ -# Signature "internals" - -```{admonition} TODO -:class: warning - - - Subpackets and how to make sense of them - - "Negotiating" signature hash algorithm based on recipients preference subpackets - - Explore viability of having multiple signatures, e.g. v4+v6? -``` - -## Notations - -## Zooming in: Packet structure diff --git a/book/source/08-signing_components.md b/book/source/08-signing_components.md new file mode 100644 index 0000000..8bfc50f --- /dev/null +++ b/book/source/08-signing_components.md @@ -0,0 +1,341 @@ + + +(component_signatures_chapter)= +# Signatures on components + +In this chapter, we'll consider OpenPGP signatures that apply to components. That is, signatures that apply to: + +- Component keys (primary keys or subkeys), or +- Identity components (User IDs or User attributes). + +This chapter adds a lot of detail to the material we discussed in the {ref}`certificates_chapter` chapter. Signatures on components are a crucial mechanism for forming OpenPGP certificates (which combine component keys and identities, via signatures on those components). + +Additionally, signatures on components play a crucial role for authentication of identities. Mechanisms for decentralized authentication are one of OpenPGP's core strengths, we'll look into how they work. + +Finally, signatures on components are also a central mechanism for life-cycle management of OpenPGP certificates and their components. This includes defining or changing expiration dates, or issuing revocations, for certificates or their components. + +## Self-signatures and third-party signatures + +There are two important scenarios to distinguish: + +- *Self-signatures*: Issued by the certificate's owner, using the primary key of the same certificate. +- *Third-party signatures*: Issued by a key that is part of a different certificate. + +### Meaning differs between self- and third-party signatures + +The meaning of a signature depends in part on who issued it. A self-signature often has a different meaning from a signature issued by a third party. + +For example: + +- A [direct key signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-direct-key-signature-type-i) issued as a self-signature can be used to set preferences and advertise features that apply to the whole certificate, while +- A similar [direct key signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-direct-key-signature-type-i) issued by a third party, which carries a [trust signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-trust-signature) subpacket, acts as a statement by the issuer that they delegate trust to the signed certificate (the issuer thereby uses the remote certificate as a trust root in the *Web of Trust*). + +Or: + +- Certifying self-signatures (type IDs `0x10` - `0x13`) are used to bind a User ID to a certificate, while +- the same signature type IDs issued by a third party are statements by the signer that they endorse the authenticity of the signed User ID to some degree. + +There are further signature types for signatures on data, as well as designated types to bind and revoke subkeys. + +## Signatures on components + +A typical use-case for a self-signature is to attach a User ID, such as a name and email address to a certificate. +This is done by calculating the signature over the User ID and the public primary key. +The resulting User ID certification (typically type 0x13, potentially type 0x10-0x12) can then be inserted into the certificate, right after the User ID packet. + +Other examples for self-signatures are binding signatures for subkeys. To add an OpenPGP subkey to a certificate, a subkey binding signature is calculated over the public primary key, followed by the public subkey. +The resulting subkey binding signature (type 0x18) can then be inserted into the certificate right after the subkey. +If the subkey itself is intended to be used as a **S**igning key, an extra step is required. +To prevent an attacker from being able to "adopt" a victims signing subkey and then being able to claim to be the origin of signatures in fact made by victim, subkey binding signatures for signing subkeys need to include an embedded "back signature" (formally known as [primary key binding signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#sigtype-primary-binding)) made by the signing key itself. + +Certifications over User IDs can also be used to certify certificates of third-parties. +If Alice is certain that `Bob Baker ` controls the key `0xB0B`, she can create a User ID certification signature for that identity and send it to Bob. +Bob can then add this signature to his certificate. +TODO: More WoT. + +```{note} +The **certify others** key flag is not required in order to issue certifying self-signatures. +This key flag is only necessary to issue valid third-party certifications. +``` + +### Revocations + +One important class of self-signatures are revocations. + +A revocation signature is used to retract the statement formed by a prior signature. +A subkey revocation signature revokes a prior subkey binding signature, while a certification revocation revokes a certification signature. +Typical use-cases for revocations are marking certificates or individual subkeys as unusable (for example, when the private key has been compromised or superseded), or marking User IDs as no longer used. + +A revocation signature can either be hard or soft. A soft revocation of a certificate invalidates it from the revocation signature's creation time onwards. This means signatures issued before the revocation remain intact. A hard revocation, by contrast, invalidates the certificate retroactively, rendering all issued signatures invalid, regardless of creation time. Soft revocations are typically used whenever a key or User ID is retired or superseded gracefully, while hard revocations can, for example, signal compromise of secret key material. + +## Self-signatures: Linking the components of a certificate + +So far we've looked at the components in an OpenPGP certificate, but certificates actually contain another set of elements, which bind the components together, and add metadata to them. + +Internally, an OpenPGP certificate consists of a sequence of OpenPGP packets. These packets are just stringed together, one after the other. When a certificate is stored in a file[^tpk], it's easy to remove some of these packets, or add new ones. + +[^tpk]: When stored in a file, OpenPGP certificates are in a format called [transferable public key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-transferable-public-keys). + +However, the owner of a certificate doesn't want a third party to add subkeys (or add [identity components](identity_components)) to their certificate, pretending that the certificate owner put those components there. + +To prevent malicious addition of components, OpenPGP uses cryptographic signatures. These signatures show that components have been added by the owner of the OpenPGP certificate (these linking signatures are issued by the primary key of the certificate). + +So while anyone can still unilaterally store unrelated subkeys and [identity components](identity_components) in an OpenPGP certificate dataset, OpenPGP implementations that read this certificate should discard components that don't have a valid cryptographic connection with the certificate. + +(Conversely, it's easy for a third party to leave out packets when passing on an OpenPGP certificate. An attacker can, for example, choose to omit revocation packets. The recipient of such a partial copy has no way to notice the omission, without access to a different source for the certificate that contains the revocation packet.) + +Note, though, that there are some cases where third parties legitimately add "unbound" packets to certificates (that is: packets that are not signed by the certificate's owner): + +- [Third-party certifications](third_party_cert) are traditionally added to the certificate that they make a statement about (this can cause problems in systems that unconditionally accept and include such certifications[^flooding]), +- OpenPGP software may add [unbound identity data](unbound_user_ids), locally. + +[^flooding]: Storing third-party identity certifications in the target OpenPGP certificate is convenient for consumers: it is easy to find all relevant certifications in one central location. However, when third parties can unilaterally add certifications, this opens an avenue for denial-of-service attacks by flooding. The SKS network of OpenPGP key servers [allowed and experienced this problem](https://dkg.fifthhorseman.net/blog/openpgp-certificate-flooding.html). + +(bind_subkey)= +### Binding subkeys to a certificate + +Linking a subkey to an OpenPGP certificate is done with a ["Subkey Binding Signature"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-subkey-binding). Such a signature signals that the "primary key wants to be associated with the subkey". + +The subkey binding signature also adds metadata. + +```{figure} diag/subkey_binding_signature.png + +Linking an OpenPGP subkey to the primary key with a binding signature +``` + +The [Signature packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-packet-tag-2) that binds the subkey to the primary key has the signature type [SubkeyBinding](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-subkey-binding-signature-si). + + +In order to specify an expiration time for the subkey, a key expiration time subpacket can be included. Note, that the validity of the subkey is bounded by that of the primary key, meaning an expired primary key causes the subkey to be invalidated, no matter the subkey expiration time. + +Note, that a subkey cannot be "older" than the primary key. The value of the subkeys creation date MUST be greater than that of the primary key. + +### Special case: Binding signing subkeys to a certificate + +Binding subkeys with the "signing" key flag is a special case. For the most part, it works the same as binding other types of subkeys, but there is an additional requirement: + +When binding a signing subkey to a primary key, it is not sufficient that the "primary key wants to be associated with the subkey." In addition, the subkey must signal that it "wants to be associated with that primary key." + +Otherwise, Alice could "adopt" Bob's signing subkey and convincingly claim that she made signatures that were in fact issued by Bob. +This is to prevent an attack where the attacker "adopts" the victims signing subkey as their own in order to claim ownership over documents which were in fact signed by the victim. +Contrary to the `SubkeyBinding` signature, which is issued by the certificates primary key, the `PrimaryKeyBinding` signature is instead created by the subkey. + +```{figure} diag/subkey_binding_signatur_for_signing_sk.png + +Linking an OpenPGP signing subkey to the primary key with a binding signature, and an embedded primary key binding signature +``` + +This additional "Primary Key Binding" Signature is informally called a "back signature" (because the subkey uses the signature to point "back" to the primary key) is an embedded `PrimaryKeyBinding` "back signature" (type 0x19). + + +### Binding identities to a certificate + +"User ID" identity components are bound to an OpenPGP certificate by issuing a self-signature ("User Attributes" work analogously). + +For example, the User ID `Alice Adams ` may be associated with Alice's certificate `AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3`. + +Alice can link a User ID to her OpenPGP certificate with a cryptographic signature. To link a User ID, a self-signature is created (usually with the signature type [PositiveCertification](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-positive-cert)). This signature is issued by the primary key. + +```{figure} diag/user_id_certification.png +--- +--- +Linking a User ID to an OpenPGP certificate +``` + +This signature is calculated over the primary key and User ID. + + +(direct_key_signature)= +### Direct key signature: Adding metadata to the primary key + +```{admonition} TODO +:class: warning + +explain metadata associated with this signature, and that c-r prefers this over primary user id. +``` + +### Revocations: Invalidating components of a certificate + +```{admonition} TODO +:class: warning + +This section only contains notes and still needs to be written +``` + +Note: certification signatures [can be made irrevocable](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-revocable). + +#### Hard vs. soft revocations + +A revocation signature may contain a subpacket indicating the reason for revocation. This subpacket contains a code which specifies why the revocation was issued. This code determines, whether the revocation is hard or soft. + +A soft revocation is typically used for graceful or planned revocations. A soft revocation can be reverted by re-validating the certificate, User ID or subkey with a fresh binding signature. +A soft revocation invalidates the target certificate beginning with the revocations creation time. + +Contrary, a hard revocation cannot be re-validated. Furthermore, a hard-revoked certificate is invalidated retroactively. + +A missing revocation reason subpacket is equivalent with a hard revocation reason. + +(third_party_cert)= +## Third-party certifications: Making statements about other people's certificates and identities + +```{admonition} TODO +:class: warning + +write +``` + +## Advanced topics + +### Certification Recipes + +As mentioned above, different signatures are used for different purposes. +In this section, we will try to give guidance on how to create certain signatures by example. + +#### Change Algorithm Preferences + +In order to change what symmetric, compression, hash or AEAD algorithms are preferred by the key owner, they can issue a direct-key signature (type 0x1F) on the primary key. +This signature should have the following structure: + +| Subpacket | Area | Critical | Mandatory | Notes | +|-----------|------|----------|-----------|-------| +| Signature Creation Time | Hashed | True | True | Current time | +| Issuer Fingerprint | Hashed | True or false | Strongly recommended | The primary key is the issuer | +| Key Flags | Hashed | True | False | Carry over key flags from previous self-signature | +| Features | Hashed | True | False | Carry over features from previous self-signature | +| Key Expiration Time | Hashed | True | False | Carry over expiration time from previous self-signature, if present | +| Hash Alg. Pref. | Hashed | False | False | New preferences | +| Comp. Alg. Pref. | Hashed | False | False | New preferences | +| Symm. Alg. Pref. | Hashed | False | False | New preferences | +| AEAD Alg. Pref. | Hashed | False | False | New preferences | + +#### Change Expiration Time + +The recommended way to change the expiration time of a certificate is by issuing a new `DirectKey` signature (type 0x1F) with an adjusted Key Expiration Time subpacket. +The structure of such a signature is the same as in the section above. +It is also possible to change the expiration date of individual User IDs (see section below) or separate subkeys (see {numref}`bind_subkey`). + +#### Add User ID + +A signature that binds a User ID to a certificate should have the following structure: + +| Subpacket | Area | Critical | Mandatory | Notes | +|-----------|------|----------|-----------|-------| +| Signature Creation Time | Hashed | True | True | Current time | +| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer | +| Primary User ID | Hashed | True | False | Optional | +| Signature Expiration Time | Hashed | True | False | Optional | + +Self-certifications over User IDs can optionally carry the same subpackets as listed in the previous table (key flags, features, algorithm preferences). +This way, separate capabilities can be assigned to different identities. + +#### Remove / Revoke User ID + +Since OpenPGP certificates are often distributed by the means of key servers, new signatures on a certificate are often "merged" into existing copies of the certificate locally by the recipient. +This means, that it is not really possible to remove signatures / User IDs from a certificate, as there is no way to communicate the intention of packet deletion to the recipient. + +So to mark a User ID as invalid, the user can publish a copy of their certificate with a `CertificationRevocation` (signature type 0x30) attached to the invalidated User ID. +This signature signals that the holder of the certificate no longer wants to be associated with that User ID. + +The structure of a certification revocation is as follows: + +| Subpacket | Area | Critical | Mandatory | Notes | +|-----------|------|----------|-----------|-------| +| Signature Creation Time | Hashed | True | True | Current time | +| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer | +| Reason for Revocation | Hashed | True | False | Decides over soft / hard revocation | + +For User ID revocations, the value of the reason subpacket can either be `0` (no reason specified) or `32`, signaling that the User ID is no longer valid. +The latter would result in a soft revocation, while a reason code of `0` is considered a hard revocation. +Omitting the reason packet altogether is also equivalent to a hard revocation. +It is recommended to issue User ID certifications using a reason code `32` and to do certificate revocations using a direct-key signature. + +(binding_subkeys)= +#### Add a Subkey + +For the purpose of key freshness, a user might want to add a new subkey to their certificate. + + +The structure is as follows: + +| Subpacket | Area | Critical | Mandatory | Notes | +|-----------|------|----------|-----------|-------| +| Signature Creation Time | Hashed | True | True | Current time | +| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer | +| Key Flags | Hashed | True | Strongly Recommended | Determine the usage of the key | +| Key Expiration Time | Hashed | True | False | Specifies the expiration date of the subkey | +| Embedded Signature | Hashed | True | If Key Flags contains **S** | Signing subkeys require embedded `PrimaryKeyBinding` signature | +| Hash Alg. Pref. | Hashed | False | False | Per key preferences | +| Comp. Alg. Pref. | Hashed | False | False | Per key preferences | +| Symm. Alg. Pref. | Hashed | False | False | Per key preferences | +| AEAD Alg. Pref. | Hashed | False | False | Per key preferences | + +Optional algorithm preference subpackets can be used to signal per-subkey preferences that deviate from those set in the certificates `DirectKey` signature. + +#### Revoke a Subkey + +Analogous to User IDs, subkeys can be revoked individually. +This is done by issuing a `SubkeyRevocation` signature (type 0x28) using the primary key. +The structure of such a signature is rather minimal: + +| Subpacket | Area | Critical | Mandatory | Notes | +|-----------|------|----------|-----------|-------| +| Signature Creation Time | Hashed | True | True | Current time | +| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer | +| Reason for Revocation | Hashed | True | False | Decides over soft / hard revocation | + +In `SubkeyRevocation` signatures, the reason subpacket cannot have value `32`, but instead may be from the range of `0-3`. +Values `1` (key superseded) and `3` (key retired and no longer used) are soft reasons, while `0` (no reason) and `2` (key compromised) are considered hard. + +#### Revoke a Certificate + +A user might want to revoke their whole certificate, rendering it unusable. +Depending on the circumstances, they might either want to revoke it softly, e.g. in case of migration to a new certificate, or they want to issue a hard revocation, e.g. in case of secret key material compromise. A soft-revoked certificate can be re-validated at a later point in time, by issuing a new certification, while a hard revocation is typically permanent. + +The recommended way to revoke a certificate is by issuing a `KeyRevocation` signature (type 0x20). +The structure of a key revocation signature is similar to that of a `CertificationRevocation` signature. + +| Subpacket | Area | Critical | Mandatory | Notes | +|-----------|------|----------|-----------|-------| +| Signature Creation Time | Hashed | True | True | Current time | +| Issuer Fingerprint | Hashed | True or false | Strongly Recommended | The primary key is the issuer | +| Reason for Revocation | Hashed | True | False | Decides over soft / hard revocation | + +For `KeyRevocation` signatures, the same constraints as for `SubkeyRevocation` signatures apply to the reason subpacket. + +#### Common Subpackets + +There are some subpackets that are expected to be included in any type of signature. + +* **Signature Creation Time**: Every OpenPGP signature MUST contain a Signature Creation Time subpacket (2) containing the timestamp at which the signature was made. This packet MUST be present in the hashed area of the signature and SHOULD be marked as critical. + +* **Issuer Fingerprint**: To be able to verify a signature, the verifier needs to know which (sub-)key was used to issue the signature in the first place. Therefore, every OpenPGP v6 signature SHOULD contain an Issuer Fingerprint subpacket (33) containing the 32 byte fingerprint of the particular component key that was used to create the signature. + +```{note} +The issuer key might be a subkey. +``` + +Since the issuer fingerprint subpacket is self-authenticating, it can either be included as a hashed or unhashed subpacket, but the authors of this book recommend to place it in the hashed area of the signature. + +### Potential subpacket conflicts and duplication + +Since the hashed and unhashed areas of a signature are just lists of subpackets, in principle they allow duplicates of the same subpacket, which might lead to conflicts. +Therefore, packets in the hashed area take precedence over the unhashed area. +However, there may still be conflicts between packets in the same area, e.g., two conflicting expiration dates, etc. +The [specification recommends](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-notes-on-subpackets) that implementations favor the last occurrence of a conflicting packet in the hashed area. + +In some cases, duplicate packets with conflicting content even make sense, e.g., if a signature was made by a version 4 issuer key whose key material was migrated from an older OpenPGP version such as v3. +In this case, either the v3 or v4 key could be used to validate the v4 signature, but since the key ID calculation scheme was changed between v3 and v4, these identifiers would differ. +Therefore, the signature could contain two isuer key ID subpackets with conflicting, but correct values. + +```{admonition} TODO +:class: warning + +- Key Flags +- Preferences +- Embedded Signature (back sig) +- Trust Signatures (amount, depth) +- Direct key signatures +``` diff --git a/book/source/09-verification.md b/book/source/09-verification.md index bee54ba..52f67f4 100644 --- a/book/source/09-verification.md +++ b/book/source/09-verification.md @@ -1,3 +1,8 @@ + + (verification_chapter)= # Verification diff --git a/book/source/10-encryption.md b/book/source/10-encryption.md index 6489040..2b48280 100644 --- a/book/source/10-encryption.md +++ b/book/source/10-encryption.md @@ -1,3 +1,8 @@ + + (encryption_chapter)= # Encryption @@ -14,6 +19,7 @@ Core concept: ## Generations of encryption +(SEIPDv2)= ### SEIPD w/ AEAD (v2) ### SEIPD (v1) @@ -28,10 +34,18 @@ Core concept: ### Implications of how a recipient cert is "addressed" (fingerprint/key-ID vs. user-ID) (preferences, expiration, revocation) +### AEAD modes: GCM + +```{admonition} TODO +:class: warning + +Produce text around discussion: https://mailarchive.ietf.org/arch/msg/openpgp/ZTYD5VJsG1k2jJBbn5zIAf5o7d4/ +``` + ## Zooming in: Packet structure ### Encryption yields a 'wrapped' openpgp packet stream ### SKESK -Also see https://flowcrypt.com/docs/guide/send-and-receive/send-password-protected.html \ No newline at end of file +Also see https://flowcrypt.com/docs/guide/send-and-receive/send-password-protected-emails.html diff --git a/book/source/11-decryption.md b/book/source/11-decryption.md index 930a1b7..a3e39dd 100644 --- a/book/source/11-decryption.md +++ b/book/source/11-decryption.md @@ -1,3 +1,8 @@ + + (decryption_chapter)= # Decryption diff --git a/book/source/12-compression.md b/book/source/12-compression.md index aa6e6d4..9e3a0f5 100644 --- a/book/source/12-compression.md +++ b/book/source/12-compression.md @@ -1,3 +1,8 @@ + + # Compression ## Zooming in: Packet structure diff --git a/book/source/13-armor.md b/book/source/13-armor.md index a50c1fe..a7870e3 100644 --- a/book/source/13-armor.md +++ b/book/source/13-armor.md @@ -1,3 +1,8 @@ + + # ASCII Armor The native format of OpenPGP data is binary. diff --git a/book/source/14-pitfalls.md b/book/source/14-pitfalls.md index cd538ca..ae611f3 100644 --- a/book/source/14-pitfalls.md +++ b/book/source/14-pitfalls.md @@ -1,3 +1,8 @@ + + # Pitfalls / Things to keep in mind ## Key IDs are really not guaranteed to be unique diff --git a/book/source/15-migration.md b/book/source/15-migration.md index 9bb57a5..94c23b2 100644 --- a/book/source/15-migration.md +++ b/book/source/15-migration.md @@ -1,3 +1,8 @@ + + # Migration from v4 to v6 ```{admonition} TODO diff --git a/book/source/16-policy.md b/book/source/16-policy.md index d85f4f4..0bc613d 100644 --- a/book/source/16-policy.md +++ b/book/source/16-policy.md @@ -1,3 +1,8 @@ + + # Algorithms and Policy ```{admonition} TODO diff --git a/book/source/17-zoom_certificates.md b/book/source/17-zoom_certificates.md index e8324cd..ca204ea 100644 --- a/book/source/17-zoom_certificates.md +++ b/book/source/17-zoom_certificates.md @@ -1,14 +1,20 @@ -# Zooming in: Packet structure of certificates and keys + -Now that we've established these concepts, and the components that OpenPGP certificates consist of, let's look at the internal details of an example certificate. +(zoom_certificates)= +# Zooming in: Packet structure of certificates + +Now that we've established the concepts and components that make up OpenPGP certificates, let's look at the internal details of an example certificate. ## A very minimal OpenPGP certificate -First, we'll look at a very minimal version of a "public key" variant of [](alice_priv). That is, an OpenPGP certificate (which doesn't contain private key material). +In this section, we will examine a very minimal version of a "public key" variant of [Alice's OpenPGP key](alice_priv), specifically an OpenPGP certificate that excludes private key material. -In this section, we use the Sequoia-PGP tool `sq` to handle and transform our example OpenPGP key, and to inspect internal OpenPGP packet data. +To achieve this, we will use the Sequoia-PGP tool `sq` to handle and transform our example OpenPGP key, as well as to inspect internal OpenPGP packet data. -Starting from [Alice's OpenPGP "private key"](alice_priv), we first produce the corresponding "public key", or certificate: +Starting from [Alice's OpenPGP private key](alice_priv), we first produce the corresponding public key/certificate using the following command: ```text $ sq key extract-cert alice.priv > alice.pub @@ -17,13 +23,15 @@ $ sq key extract-cert alice.priv > alice.pub (split_alice)= ### Splitting the OpenPGP certificate into packets -One way to produce a very minimal version of Alice's certificate is to split the data in `alice.pub` into its component packets, and join only the relevant ones back together into a new variant. +To create a very minimal version of Alice's certificate, we will split the data in `alice.pub` into its component packets and reassemble only the relevant ones back into a new variant. + +Execute the following command to achieve this: ```text $ sq packet split alice.pub ``` -With this command, `sq` generates a set of files, each containing an individual OpenPGP packet of the original full certificate in `alice.pub`: +With this command, `sq` generates a set of files, each containing an individual OpenPGP packet extracted from the original full certificate in `alice.pub`: ```text alice.pub-0--PublicKey @@ -38,38 +46,34 @@ alice.pub-8--PublicSubkey alice.pub-9--Signature ``` -```{admonition} VISUAL -:class: warning -Show a very abstract diagram of the packets of Alice's OpenPGP certificate (above): -- Public-Key packet -- Direct Key Signature -- User ID -- Certifying self-signature for User ID -- Public-Subkey packet -- Subkey binding signature -- Public-Subkey packet -- Subkey binding signature -- Public-Subkey packet -- Subkey binding signature +```{figure} diag/certificate_packet_list.png + +Overview of the packets in Alice's OpenPGP certificate ``` -### Joining packets into an OpenPGP certificate +This process allows us to focus on the specific packets within Alice's OpenPGP certificate. -For our first step, we'll use just the first two of the packets of Alice's certificate, and join them together as a very minimal certificate: +### Assembling packets into an OpenPGP certificate + +In this step, we'll merge the first two packets of Alice's certificate to create a very minimal certificate: + +Execute the following: ```text $ sq packet join alice.pub-0--PublicKey alice.pub-1--Signature --output alice_minimal.pub ``` +This command combines the contents of `alice.pub-0--PublicKey` and `alice.pub-1--Signature` into a single file named `alice_minimal.pub`. + ### Inspecting this certificate This version of Alice's certificate contains just two packets: -- The [*Public-Key packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats) for the primary key, and -- A [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key) (a self-signature that binds metadata to the primary key). +- the [*Public-Key packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats) for the primary key, and +- a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key), which is a self-signature that binds metadata to the primary key. -This is the shape of the packets we'll be looking at, in the following two sections: +This is the shape of the packets we'll explore in the subsequent sections: ```{figure} diag/pubcert-minimal.png :width: 40% @@ -87,9 +91,9 @@ This diagram needs adjustments about We could show repeat-copies of the individual packet visualization again, below for each packet-related section. ``` -In the real world, you won't usually encounter an OpenPGP certificate that is quite this minimal. However, this is technically a valid OpenPGP certificate (and we'll add more components to it, later in this section). +In real-world scenarios, OpenPGP certificates are typically far more complex than this minimal example. However, this is indeed a valid OpenPGP certificate. In the following sections, we will introduce more components to this certificate, increasing its complexity and exploring their details. -In ASCII-armored representation, this very minimal key looks like this: +In ASCII-armored representation, this very minimal key appears as follows: ```text -----BEGIN PGP PUBLIC KEY BLOCK----- @@ -103,18 +107,20 @@ gAIl6FM5SWuQxg12j0S07ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L -----END PGP PUBLIC KEY BLOCK----- ``` -We'll now decode this OpenPGP data, and inspect the two packets in detail. +The output of `sq` is presented as a block of text. We will now decode this OpenPGP data and inspect the two packets it contains. -To inspect the internal structure of the OpenPGP data, we run the Sequoia-PGP tool `sq`, using the `packet dump` subcommand. The output of `sq` is one block of text, but to discuss the content of each packet we'll break the output up into sections here: +To achieve this, we will use the Sequoia-PGP tool `sq` and run the `packet dump` subcommand: ```text $ sq packet dump --hex alice_minimal.pub ``` +This will allow us to gain a detailed understanding of the packet contents. + (public_key)= ### Public-Key packet -The output now starts with a (primary) [Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats): +The output begins with a (primary) [Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-packet-formats): ```text Public-Key Packet, new CTB, 2 header bytes + 42 bytes @@ -136,37 +142,45 @@ Public-Key Packet, new CTB, 2 header bytes + 42 bytes 00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e ``` -The Public-Key packet consists in large part of the actual cryptographic key data. Let's look at the packet field by field: +The Public-Key packet consists primarily of the cryptographic key data. Let's look at the packet field by field: -- `CTB: 0xc6`[^CTB]: The [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers) for this packet. The binary representation of the value `0xc6` is `11000110`. Bits 7 and 6 show that the packet is in *OpenPGP packet format* (as opposed to in *Legacy packet format*). The remaining 6 bits encode the type ID's value: "6". This is the value for a Public-Key packet, as shown in the list of [packet type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-tags). -- `length: 0x2a`: The remaining length of this packet. +**OpenPGP packet syntax** -The packet type id defines the semantics of the remaining data in the packet. We're looking at a Public-Key packet, which is a kind of [Key Material Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-key-material-packets). +The first fields of a packet are governed by the general [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-syntax): -- `version: 0x06`: The key material is in version 6 format +- `CTB: 0xc6`[^CTB]: This is the [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers) for this packet. The binary representation of the value `0xc6` is `11000110`. The first two bits show that the packet is in *OpenPGP packet format* (as opposed to in *Legacy packet format*) and the remaining 6 bits encode the type ID value, which is "6." This type ID value corresponds to a Public-Key packet, as listed in the [packet type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-tags). -This means that the next part of the packet follows the structure of [Version 6 Public Keys](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-6-public-keys) +- `length: 0x2a`: This indicates the remaining length of this packet. -- `creation_time: 0x6516eaa6`: "The time that the key was created" (also see [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-time-fields)) -- `pk_algo: 0x1b`: "The public-key algorithm ID of this key" (decimal value 27, see the list of [Public-Key Algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)) -- `public_len: 0x00000020`: "Octet count for the following public key material" (in this case, the length of the following `ed25519_public` field) -- `ed25519_public`: [Algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-part-for-ed2) of the public key material (the format is based on the value of `pk_algo`), in this case 32 bytes of Ed25519 public key +**Public-Key packet syntax** -[^CTB]: Sequoia uses the term CTB (Cipher Type Byte) to refer to the RFC's [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers). In previous versions, the RFC called this field "Packet Tag". +The packet type ID ("6") defines the semantics of the following data within the packet. In this case, it is a Public-Key packet, which is a kind of [Key Material Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-key-material-packets). -```{tip} +- `version: 0x06`: The key material is in version 6 format. This means that the next part of the packet adheres to the structure of [Version 6 Public Keys](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-6-public-keys). -The overall structure of OpenPGP packets is described in the [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-syntax) chapter of the RFC. -``` +- `creation_time: 0x6516eaa6`: This field represents the key's creation time. (See also [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-time-fields)). + +- `pk_algo: 0x1b`: This corresponds to the key's public-key algorithm ID, which has a decimal value of 27. Refer to the list of [Public-Key Algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)) for more details. + +- `public_len: 0x00000020`: This field specifies the octet count for the subsequent public key material. In this case, it represents the length of the following `ed25519_public` field. + +- `ed25519_public`: This is the [algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-part-for-ed2) of the public key material. The format is based on the value of `pk_algo`, which, in this case, is 32 bytes of Ed25519 public key data. + +[^CTB]: Sequoia uses the term CTB (Cipher Type Byte) to refer to the RFC's [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-headers). In earlier RFC versions, this field was known as the "Packet Tag." Note that the *Public-Key packet* contains only the public part of the key. +```{figure} diag/public-key_packet.png + +Structure of a Public-Key packet. +``` + (zooming_in_dks)= ### Direct Key Signature -The next packet is a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key), which is bound to the primary key (the file `alice.pub-1--Signature` contains this packet). +The next packet in the certificate is a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#sigtype-direct-key), which plays a crucial role in binding specific information to the primary key. This signature is contained within the file `alice.pub-1--Signature`. -This packet "binds the information in the signature subpackets to the key". Each entry under "Signature Packet -> Hashed area" is one signature subpacket, for example, including information about algorithm preferences (*symmetric algorithm preference* and *hash algorithm preferences*). +This packet binds the data within the signature subpackets with the primary key. Each entry under "Signature Packet -> Hashed area" is one signature subpacket, providing essential information such as algorithm preferences, including *symmetric algorithm preference* and *hash algorithm preferences*. ```text Signature Packet, new CTB, 2 header bytes + 182 bytes @@ -236,83 +250,146 @@ Signature Packet, new CTB, 2 header bytes + 182 bytes 000000b0 54 01 f9 5f 81 41 90 0e ``` -Let’s look at the packet field by field: +Below is a field-by-field examination of the packet: -- `CTB: 0xc2`: The Packet type ID for this packet. Bits 7 and 6 show that the packet is in “OpenPGP packet format” (as opposed to in “Legacy packet format”). The remaining 6 bits encode the type ID’s value: “2.” This is the value for a Signature packet. -- `length: 0xb6`: The remaining length of this packet. +**OpenPGP packet syntax** -The packet type ID defines the semantics of the remaining data in the packet. We're looking at a [Signature packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-packet), so the following data is interpreted accordingly. +The first fields of a packet are governed by the general [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-packet-syntax): -- `version: 0x06`: This is a version 6 signature (some of the following packet format is specific to this signature version). -- `type: 0x1f`: The [Signature Type](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-types) -- `pk_algo: 0x1b`: Public-key algorithm ID (decimal 27, corresponds to [Ed25519](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)) -- `hash_algo: 0x0a`: Hash algorithm ID (decimal 10, corresponds to [SHA2-512](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-hash-algorithms)) -- `hashed_area_len: 0x0000003d`: Length of the following hashed subpacket data +- `CTB: 0xc2`: This field indicates the Packet type ID for this packet. Bits 7 and 6 show that the packet is in “OpenPGP packet format.” The remaining 6 bits encode the type ID’s value, which is “2” for a Signature packet. -The next part of this packet contains hashed subpacket data. A subpacket data set in an OpenPGP Signature contains a list of zero or more Signature subpackets. +- `length: 0xb6`: This field shows the remaining length of this packet. -There are two sets of subpacket data in a Signature: hashed, and unhashed. The difference is that the hashed subpackets are protected by the digital signature of this packet, while the unhashed subpackets are not. +**Signature packet syntax** -The following subpacket data consists of sets of "subpacket length, subpacket type ID, data." We'll show the information for each subpacket as one line, starting with the [subpacket type description](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-subpacket-specifi) (based on the subpacket type ID). Note that bit 7 of the subpacket type ID signals if that subpacket is ["critical"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-5.2.3.7-10). +The packet type ID (“2”) defines the semantics of the remaining data in the packet. In this case, as it indicates a [Signature packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-packet), the following data is specific to this packet type: + +- `version: 0x06`: This is a version 6 signature. + +- `type: 0x1f`: This indicates the [Signature Type](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-types). + +- `pk_algo: 0x1b`: This specifies the Public-Key algorithm ID, with decimal 27 corresponding to [Ed25519](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms)). + +- `hash_algo: 0x0a`: This specifies the hash algorithm ID, with decimal 10 corresponding to [SHA2-512](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-hash-algorithms)). + +- `hashed_area_len: 0x0000003d`: This specifies the length of the following hashed subpacket data. + +The next segment of this packet contains the hashed subpacket data. + +In OpenPGP Signatures, there are two sets of subpacket data: hashed and unhashed. Hashed subpackets are protected by the digital signature of the packet, while unhashed subpackets are not. + +A subpacket data set in an OpenPGP Signature contains a list of zero or more Signature subpackets. + +The following subpacket data consists of sets of "subpacket length, subpacket type ID, data." Each subpacket is displayed as one line, starting with the [subpacket type description](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-subpacket-specifi) (based on the subpacket type ID). Note that bit 7 of the subpacket type ID signals if that subpacket is ["critical."](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-5.2.3.7-10) ```{note} -Critical here means: the receiver must be able to interpret the subpacket and is expected to fail, otherwise. Non-critical subpackets may be ignored by the receiver. +Critical here means that the receiver must interpret the subpacket and is expected to fail, otherwise. Non-critical subpackets may be ignored by the receiver. ``` -- [Signature creation time](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-creation-subpacket) (subpacket type 2, **critical**): `0x6516eaa6` (also see [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-time-fields)) -- [Key expiration time](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-expiration-subpacket) (subpacket type 9, **critical**): `0x05a48fbd` (defined as number of seconds after the key creation time) -- [Preferred symmetric ciphers for v1 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#preferred-v1-seipd) (type 11): `0x09 0x07`. (These values [correspond to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#symmetric-algos): *AES with 256-bit key* and *AES with 128-bit key*) -- [Preferred hash algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#preferred-hashes-subpacket) (subpacket type 21): `0x0a 0x08`. (These values [correspond to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-hash-algorithms): *SHA2-512* and *SHA2-256*) -- [Key flags](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-flags) (subpacket type 27, **critical**): `0x01`. (This value [corresponds](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-key-flags) to the *certifications* key flag) -- [Features](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#features-subpacket) (subpacket type 30): `0x01`. (This value [corresponds](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-features) to: *Symmetrically Encrypted Integrity Protected Data packet version 1*) -- [Issuer fingerprint](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#issuer-fingerprint-subpacket) (subpacket type 33): `aaa18cbb254685c58358320563fd37b67f3300f9fb0ec457378cd29f102698b3` (this is the fingerprint of the component key that issued the signature in this packet. Not that here, the value is the primary key fingerprint of the certificate we're looking at.) +The subpacket details are as follows: -The next part of this packet contains "unhashed subpacket data": +- [**Signature Creation Time**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#signature-creation-subpacket) + - Type: `2` + - Critical: `Yes` + - Value: `0x6516eaa6` + - Notes: See also [Time Fields](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-time-fields). -- `unhashed_area_len: 0x0000000a`: Length of the following unhashed subpacket data (value: 10 bytes). +- [**Key Expiration Time**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-expiration-subpacket) + - Type: `9` + - Critical: `Yes` + - Value: `0x05a48fbd` + - Notes: Defined as number of seconds after the key creation time -As above, the following subpacket data consists of sets of "subpacket length, subpacket type id, data." In this case, only subpacket follows: +- [**Preferred Symmetric Ciphers for v1 SEIPD**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#preferred-v1-seipd) + - Type: `11` + - Critical: `No` + - Value: `0x09 0x07` + - Notes: Values correspond to *AES with 256-bit key* and *AES with 128-bit key* -- [Issuer Key ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#issuer-keyid-subpacket) (subpacket type 16): `aaa18cbb254685c5` (this is the shortened version 6 *Key ID* of the fingerprint of this certificate's primary key) +- [**Preferred Hash Algorithms**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#preferred-hashes-subpacket) + - Type: `21` + - Critical: `No` + - Value: `0x0a 0x08` + - Notes: Values correspond to *SHA2-512* and *SHA2-256*. + +- [**Key Flags**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#key-flags) + - Type: `27` + - Critical: `Yes` + - Value: `0x01` + - Notes: Value corresponds to the *certifications* key flag. + +- [**Features**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#features-subpacket) + - Type: `30` + - Critical: `No` + - Value: `0x01` + - Notes: Value corresponds to *Symmetrically Encrypted Integrity Protected Data packet version 1* + +- [**Issuer Fingerprint**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#issuer-fingerprint-subpacket) + - Type: `33` + - Critical: `No` + - Value: `aaa18cbb254685c58358320563fd37b67f3300f9fb0ec457378cd29f102698b3` + - Notes: The fingerprint identifies the component key that issued the signature in this packet. In this instance, the value is the primary key fingerprint of the certificate we're looking at. + +The next part of this packet contains unhashed subpacket data: + +- `unhashed_area_len: 0x0000000a`: length of the following unhashed subpacket data (value: 10 bytes). + +As above, the following subpacket data consists of sets of subpacket length, subpacket type id, and data. In this case, only one subpacket follows: + +- [**Issuer Key ID**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#issuer-keyid-subpacket) + - Type: `16` + - Critical: `No` + - Value: `aaa18cbb254685c5` + - Notes: This is the shortened version 6 *Key ID* of the fingerprint of this certificate's primary key. This concludes the unhashed subpacket data. -- `digest_prefix: 0x6747`: "The left 16 bits of the signed hash value" -- `salt_len, salt`: A random [salt value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-advantages-of-salted-signat) (the size must be [matching for the hash algorithm](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#hash-algorithms-registry)) -- `ed25519_sig`: [Algorithm-specific](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-fields-for-ed2) representation of the signature (in this case: 64 bytes of Ed25519 signature) +This next section shows the remaining fields of this signature packet, which relate to the cryptographic digital signature: -The signature is calculated over a hash. The hash, in this case, is calculated over the following data (for details, see [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC): +- `digest_prefix: 0x6747`: the left 16 bits of the signed hash digest -- The signature's salt -- A serialized form of the primary key's public data -- A serialized form of this direct key signature packet (up to, but excluding the unhashed area) +- `salt_len, salt`: a random [salt value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-advantages-of-salted-signat) with size [matching the hash algorithm](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#hash-algorithms-registry)) +- `ed25519_sig`: [algorithm-specific](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-algorithm-specific-fields-for-ed2) representation of the signature (here: 64 bytes of Ed25519 signature) + +The hash digest is calculated from the following data (see [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC): + +- the signature's salt +- the serialized primary key's public data +- the serialized direct key signature packet (excluding the unhashed area) + +The signature is calculated from this hash digest. + +```{figure} diag/direct_key_signature_packet.png + +Structure of a direct key signature packet. +``` (zoom_enc_subkey)= ## Encryption subkey -Now we'll look at a subkey in Alice's certificate. An OpenPGP subkey, when it is linked to an OpenPGP certificate (via its primary key), consists of two elements: +Let's now look at a subkey in Alice's OpenPGP certificate. A subkey, when linked to an OpenPGP certificate via its primary key, consists of two elements: - a key packet that contains the component key itself, and -- a signature packet that links this component key to the primary key (and thus implicitly to the full OpenPGP certificate). +- a signature packet that links this component key to the primary key and, implicitly, to the full OpenPGP certificate. -In this section, we'll use the files that contain individual packets of Alice's certificate, which we split apart above. In this split representation of Alice's certificate, the encryption subkey happens to be stored in `alice.pub-4--PublicSubkey`, and the associated binding self-signature for the subkey in `alice.pub-5--Signature`. +We will use the files containing individual packets of Alice's certificate, which we separated above. In this split representation, the encryption subkey is stored in `alice.pub-4--PublicSubkey`, while the associated binding self-signature is stored in `alice.pub-5--Signature`. ````{note} -It's common to look at a packet dump for a full OpenPGP certificate, like this: +It's common to look at a packet dump for a full OpenPGP certificate as shown below: ```text $ sq packet dump --hex alice.pub ``` -That command shows the details for the full series of packets in an OpenPGP certificate (recall the list of [packets of Alice's certificate](split_alice)). Finding a particular packet in that list can take a bit of focus and practice though. +This command shows the details for the full series of packets in an OpenPGP certificate (refer to the list of [packets of Alice's certificate](split_alice)). Finding a particular packet in that list can take a bit of focus and practice though. -In the following sections we're making it a bit easier for ourselves, and directly look at individual packets, from the files we created with `sq packet split`, above. +In the following sections,we make it easier for ourselves by directly examining individual packets from the files we created with `sq packet split` above. ```` ### Public-Subkey packet -First, we'll look at the *Public-Subkey packet* that contains the component key data of this subkey: +We'll now look at the *Public-Subkey packet* that contains the component key data of this subkey: ```text $ sq packet dump --hex alice.pub-4--PublicSubkey @@ -335,17 +412,18 @@ Public-Subkey Packet, new CTB, 2 header bytes + 42 bytes 00000020 35 2a 46 01 f3 cc 00 f5 4a 09 3e 3f ``` -Notice that the structure of this *Public-Subkey packet* is the same as the *Public-Key Packet* of the primary key, [above](public_key). Only the content of the two packets differs in some points: +Notice that the structure of this *Public-Subkey packet* mirrors the primary key's [*Public-Key packet*](public_key) above. However, there are notable differences between the two packets: - The packet type ID (`CTB`) in this packet shows type 14 ([*Public-Subkey packet*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-subkey-packet-tag-14)). -- The `pk_algo` value is set to `0x19` (decimal 25), which [corresponds to](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms) X25519. Note that even though both the primary key and this subkey use a cryptographic mechanism based on Curve25519, this encryption key uses Curve 25519 in a different way (X25519 is a Diffie–Hellman function built out of Curve25519). -- Accordingly, the public part of the cryptographic key pair is labeled with the corresponding name: `x25519_public` (however, note that this difference only reflects the semantics of the field, which is implied by the value of `pk_algo`. The actual data consists of just 32 bytes of cryptographic key material, without any type information.) + +- The `pk_algo` value is set to `0x19` (decimal 25), which [corresponds to X25519](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-public-key-algorithms). Notably, though both the primary key and this subkey use a cryptographic mechanism based on Curve25519, the encryption key uses Curve 25519 in a different way: namely, X25519 is a Diffie–Hellman function constructed from Curve25519. +- Accordingly, the public part of the cryptographic key pair is labeled `x25519_public`, as implied by the value (`0x19`) of `pk_algo`. However, the actual data is just 32 bytes of cryptographic key material, without any type information. ### Subkey binding signature -The subkey packet above by itself is disconnected from the OpenPGP certificate that it is a part of. The link between the subkey and the full OpenPGP key is made with a cryptographic signature, which is issued by the OpenPGP key's primary key. +The aforementioned subkey packet is disconnected from the OpenPGP certificate to which it belongs. The link between the subkey and the complete OpenPGP certificate is made with a cryptographic signature, generated by primary key of the OpenPGP certificate. -The type of signature that is used for this is called a *subkey binding signature*, because it "binds" (as in "connects") the subkey to the rest of the key. +The type of signature is called a *subkey binding signature*, because it "binds" or connects the subkey to the rest of the key. ```{admonition} VISUAL :class: warning @@ -362,9 +440,10 @@ Should this text go elsewhere? - 4.2.3? - ch 6? ``` -In addition to its core purpose of making the connection, this signature also contains additional metadata about the subkey. One reason why this metadata is in a binding signature (and not in the subkey packet) is that it may change over time. The subkey packet itself may not change over time. So metadata about the subkey that can change is stored in self-signatures: if the key holder wants to change some metadata (for example, the key's expiration time), they can issue a newer version of the same kind of signature. Receiving OpenPGP software will then understand that the newer self-signature supersedes the older signature, and that the metadata in the newer signature reflects the most current intent of the key holder. -Note that this subkey binding signature packet is quite similar to the Direct Key Signature we discussed packet above. Both signatures perform the same function in terms of adding metadata to a component key. In particular, the hashed subpacket data contains many of the same pieces of metadata. +The signature does more than just bind the subkey; it also carries additional metadata about the subkey. This metadata is in the binding signature, and not in the subkey packet, because it may change over time, while the subkey packet itself remains unchanged. This evolving metadata is stored in self-signatures: if the key holder wants to modify the metadata (for example, to change the key's expiration time), a newer version of the same signature type can be issued. The recipient OpenPGP software will recognize that the newer self-signature supersedes the older one, and that the metadata in the newer signature reflects the most current intent of the key holder. + +Note that this subkey binding signature packet is quite similar to the Direct Key Signature discussed above. Both signatures serve a similar purpose in adding metadata to a component key, particularly as the hashed subpacket data contains much of the same metadata elements. ```text $ sq packet dump --hex alice.pub-5--Signature @@ -422,30 +501,32 @@ Signature Packet, new CTB, 2 header bytes + 171 bytes 000000a0 41 36 1b 2b 60 09 f2 d9 19 f4 41 12 0b ``` -We'll go over this packet dump in less detail, since its structure mirrors the *Direct Key Signature* (described above) very closely. +The analysis of this packet dump will be less extensive, given that its structure mirrors the *Direct Key Signature* explored above. -The first difference is in the `type` field, showing that this signature is of type `0x18` ([Subkey Binding Signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-subkey-binding-signature-si)). +One notable difference is the `type` field, showing that this signature is of type `0x18` ([Subkey Binding Signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-subkey-binding-signature-si)). -The `pk_algo` of this signature is informed by the algorithm of the primary key (`0x1b`, corresponding to Ed25519). The signature in this packet is issued by the primary key, so by definition it uses the signing algorithm of the primary key (that is: the algorithm used to produce the cryptographic signature in this packet is entire independent of the `pk_algo` of the key material of this subkey itself, which uses the X25519 mechanism). +The `pk_algo` value of this signature derives from the algorithm of the primary key (`0x1b`, corresponding to Ed25519). This signature is issued by the primary key, thus using the signing algorithm of the primary key. (The algorithm used to produce the cryptographic signature in this packet is entirely independent of the `pk_algo` of the key material of this subkey itself, which uses the X25519 mechanism.) As shown in the text at the top of this packet dump, the hashed subpacket data contains four pieces of information: -- Signature creation time: `2023-09-29 15:17:58 UTC` (**critical**) -- Key expiration time: `P1095DT62781S` (**critical**) -- Key flags: `EtEr` (**critical**) (encryption for communication, encryption for storage) -- Issuer Fingerprint: `AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3` +- signature creation time: `2023-09-29 15:17:58 UTC` (**critical**) +- key expiration time: `P1095DT62781S` (**critical**) +- key flags: `EtEr` (**critical**) (encryption for communication, encryption for storage) +- issuer fingerprint: `AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3` -The remainder of the packet has the same content as the *Direct Key Signature* above: -- A 16 bit digest prefix -- A salt value -- The cryptographic signature itself +The rest of the packet mirrors the *Direct Key Signature* discussed above: +- a 16-bit digest prefix +- a salt value +- the cryptographic signature itself -The signature is calculated over a hash. The hash, in this case, is calculated over the following data (for details, see [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC): +The signature is calculated over a hash digest. In this case, the hash digest is derived from the following data: -- The signature's salt -- A serialized form of the primary key's public data -- A serialized form of the subkey's public data -- A serialized form of this subkey binding signature packet (up to, but excluding the unhashed area) +- the signature's salt +- the serialized primary key's public data +- the serialized subkey's public data +- the serialized subkey binding signature packet (excluding the unhashed area) + +Refer to [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC for details. ## Signing subkey @@ -562,15 +643,15 @@ Signature Packet, new CTB, 3 header bytes + 325 bytes (zooming_in_user_id)= ## Adding an identity component -Now we'll look at an identity that is associated with Alice's certificate. +In this section, we'll look at an identity associated with Alice's certificate. -User IDs are a mechanism for connecting [identities](identity_components) with an OpenPGP certificate. Traditionally, User IDs contain a string that combines a name and an email address. +User IDs are a mechanism for connecting [identities](identity_components) with an OpenPGP certificate. Typically, a User ID is a string combining a name and an email address. -Like [above](zoom_enc_subkey), to look at the internal packet structure of this identity and its connection the OpenPGP certificate, we'll inspect the two individual packets that constitute the identity component, the [User ID packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13), in the file `alice.pub-2--UserID`, and the certifying self-signature a [Positive certification of a User ID and Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-positive-certification-of-a) in `alice.pub-3--Signature` (these packets are an excerpt of Alice's full OpenPGP private key). +To understand the internal packet structure of this identity and its connection to the OpenPGP certificate, we'll examine two packets that constitute the identity component. One is the [User ID packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13), located in the file `alice.pub-2--UserID`, which contains identity information. The other is a certifying self-signature, specifically a [Positive certification of a User ID and Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-positive-certification-of-a) located in the file `alice.pub-3--Signature`. This certification, issued after substantial verification of the identity claim, validates the association between the User ID and the certificate's public key. These packets are snippets from Alice's full OpenPGP certificate. ### User ID packet -First, let's look at the User ID packet, which encodes an identity that Alice has connected to her OpenPGP certificate: +First, let's look at the User ID packet, which encodes an identity that is associated with an OpenPGP certificate: ```text $ sq packet dump --hex alice.pub-2--UserID @@ -583,17 +664,19 @@ User ID Packet, new CTB, 2 header bytes + 19 bytes 00000010 2e 6f 72 67 3e ``` -- `CTB: 0xcd`: The Packet type ID for this packet. Bits 7 and 6 show that the packet is in “OpenPGP packet format” (as opposed to in “Legacy packet format”). The remaining 6 bits encode the type ID’s value: “13.” This is the value for a [User ID packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13). -- `length: 0x13`: The remaining length of this packet (here: 19 bytes). -- `value`: 19 bytes of data that contain UTF-8 encoded text. The value corresponds to the string ``. With this identity component, Alice states that she uses (and has control of) this email address. Note that the email address is enclosed in `<` and `>` characters, following [RFC 2822](https://www.rfc-editor.org/rfc/rfc2822) conventions. +- `CTB: 0xcd`: This is the packet type ID for this packet. Bits 7 and 6 show that the packet is in “OpenPGP packet format” (not “Legacy packet format”). The remaining 6 bits encode the type ID’s value: “13,” which is the value for a [User ID packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-user-id-packet-tag-13). -So, a User ID packet is really just a string, marked as a User ID by the packet type id. +- `length: 0x13`: This field shows the remaining length of the packet (here: 19 bytes). + +- `value`: This comprises 19 bytes of data that contain UTF-8 encoded text. The value corresponds to the string ``. With this identity component, Alice asserts usage and control over the specified email address. Note that the email address is enclosed in `<` and `>` characters, in line with the conventions of [RFC 2822](https://www.rfc-editor.org/rfc/rfc2822). + +Essentially, a User ID packet is just a string marked as a User ID by the packet type ID. ### Linking the User ID with a certification self-signature -As above, when [linking a subkey](zoom_enc_subkey) to the OpenPGP certificate, a self-signature is used to connect this new component to the certificate. +Similar to [linking a subkey](zoom_enc_subkey) to the OpenPGP certificate, a self-signature is used to connect this new component to the certificate. -To bind identities to a certificate with a self-signature, one of the signature types `0x10` - `0x13` can be used. Here, the signature type `0x13` (*positive certification*) is used. +To bind identities to a certificate with a self-signature, signature types `0x10` - `0x13` can be used. Here, the signature type `0x13` (*positive certification*) is used. ```text $ sq packet dump --hex alice.pub-3--Signature @@ -668,13 +751,13 @@ Signature Packet, new CTB, 2 header bytes + 185 bytes ``` -We'll go over this packet dump in less detail, since its structure closely mirrors the [Direct Key Signature](zooming_in_dks) discussed above. +Because this packet structure closely mirrors the [Direct Key Signature](zooming_in_dks) discussed above, we will cover this succinctly. -We're again looking at a Signature packet. Its `type` is `0x13` ([corresponding](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-types) to a *positive certification* signature). +We're again looking at a Signature packet. Its `type` is `0x13` ([corresponding to a *positive certification* signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-signature-types)). -The public key algorithm and hash function used for this signature are Ed25519 and SHA512. +The designated public key algorithm and hash function for this signature are Ed25519 and SHA512, respectively. -As shown in the text at the top of this packet dump, the hashed subpacket data contains the following metadata: +As shown in the text atop this packet dump, the hashed subpacket data contains the following metadata: - Signature creation time: `2023-09-29 15:17:58 UTC` (**critical**) - Key expiration time: `P1095DT62781S` (**critical**) @@ -683,16 +766,16 @@ As shown in the text at the top of this packet dump, the hashed subpacket data c - Primary User ID: `true` (**critical**) - Key flags: `C` (**critical**) - Features: `MDC` -- Issuer Fingerprint: `AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3` +- Issuer fingerprint: `AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3` -This is a combination of metadata about the User ID itself (including defining this User ID as the *primary User ID* of this certificate), algorithm preferences that are associated with this identity, and settings that apply to the primary key. +This is a combination of metadata about the User ID itself (designating this User ID as the *primary User ID* of this certificate), algorithm preferences for this identity, and settings that apply to the primary key. ````{note} -For historical reasons, the self-signature that binds the primary User ID to the certificate also contains subpackets that apply not to the User ID, but to the primary key itself. +Historically, the self-signature that binds the primary User ID to the certificate also contains subpackets relevant not to the User ID, but to the primary key itself. Setting key expiration time and key flags on the primary User ID self-signature is one mechanism to configure the primary key. -The interaction between metadata on direct key signatures and User ID binding self-signatures [is subtle](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-notes-on-self-signatures), and there are changes between version 6 and version 4. +The interaction between metadata on direct key signatures and User ID binding self-signatures [is subtle](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-notes-on-self-signatures), with changes between version 6 and version 4. ```{admonition} TODO @@ -703,16 +786,18 @@ The interaction between metadata on direct key signatures and User ID binding se ```` -Followed, again, by the (informational) unhashed subpacket area. +This section is followed, again, by the (informational) unhashed subpacket area. -And finally, a salt value for the signature and the signature itself. +Subsequently, we see a salt value for the signature and the signature itself. -The signature is calculated over a hash. The hash, in this case, is calculated over the following data (for details, see [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC): +The signature is calculated over a hash. The hash, in this case, is derived from the following data: -- The signature's salt -- A serialized form of the primary key's public data -- A serialized form of the User ID -- A serialized form of this self-signature packet (up to, but excluding the unhashed area) +- the signature's salt +- the serialized primary key's public data +- the serialized User ID + This section specifies- the serialized self-signature packet (excluding the unhashed area) + +Refer to [Computing Signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-11.html#name-computing-signatures) in the RFC for details. ## Certifications (Third Party Signatures) diff --git a/book/source/18-zoom_private_keys.md b/book/source/18-zoom_private_keys.md index f8eadab..2c5bbcb 100644 --- a/book/source/18-zoom_private_keys.md +++ b/book/source/18-zoom_private_keys.md @@ -1,3 +1,9 @@ + + +(zoom_private)= # Zooming in: Packet structure of private key material ## A look at Alice's (unencrypted) private key packets @@ -12,7 +18,16 @@ $ sq packet dump --hex alice.priv ### Primary Secret-Key packet -The output starts with the (primary) [Secret-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-key-packet-formats): +The output starts with the (primary) [Secret-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-secret-key-packet-formats). + +This is the structure of the Secret-Key packet we will now look at. + +```{figure} diag/secret-key_packet.png + +Structure of a Secret-Key packet. +``` + +The output of Sequoia's `sq packet dump` for this packet: ```text Secret-Key Packet, new CTB, 2 header bytes + 75 bytes diff --git a/book/source/19-zoom_signatures.md b/book/source/19-zoom_signatures.md index 4de3db3..f384ef4 100644 --- a/book/source/19-zoom_signatures.md +++ b/book/source/19-zoom_signatures.md @@ -1 +1,231 @@ + + +(zoom_sign_data)= # Zooming in: Packet structure of data signatures + +In this chapter, we'll create signatures using [Alice's private key](alice_priv) material, and inspect the packet structure of those signatures. + +In some examples, we'll use a test-message that contains the string `hello world` followed by one line feed (`0x0a`) character: + +```text +$ echo "hello world" > message.txt +``` + +## Detached signature + +We can produce a detached signature for this "hello world" message, using Alice's private signing key material: + +```text +$ sq sign --detached --signer-file alice.pgp message.txt +-----BEGIN PGP SIGNATURE----- + +wpgGABsKAAAAKQWCZT0tDyIhBtB7JOyRoU3SQKwtU+bIqeBUlJpBIi6nOFdu0Zyu +o9yZAAAAANueIJCkVJ5aC1Zw485o7Y72uHPnk7ktkZyhKH2MuHjCdIHQU0qe/8bR +0B3ywHNzLwUoqj0efYWhj6XeXa08haxUH7i50MEDjfFrPc281B0C5fiiGN4PYc76 +B8tA2/ZjsSgHCw== +=n8EV +-----END PGP SIGNATURE----- +``` + +And inspect the packet structure of this signature: + +```text +$ sq packet dump --hex detached-sig.txt +Signature Packet, new CTB, 2 header bytes + 152 bytes + Version: 6 + Type: Binary + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-10-28 15:47:27 UTC (critical) + Issuer Fingerprint: D07B24EC91A14DD240AC2D53E6C8A9E054949A41222EA738576ED19CAEA3DC99 + Digest prefix: DB9E + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 98 length + 00000002 06 version + 00000003 00 type + 00000004 1b pk_algo + 00000005 0a hash_algo + 00000006 00 00 00 29 hashed_area_len + 0000000a 05 subpacket length + 0000000b 82 subpacket tag + 0000000c 65 3d 2d 0f sig creation time + 00000010 22 subpacket length + 00000011 21 subpacket tag + 00000012 06 version + 00000013 d0 7b 24 ec 91 a1 4d d2 40 ac 2d 53 e6 issuer fp + 00000020 c8 a9 e0 54 94 9a 41 22 2e a7 38 57 6e d1 9c ae + 00000030 a3 dc 99 + 00000033 00 00 00 00 unhashed_area_len + 00000037 db digest_prefix1 + 00000038 9e digest_prefix2 + 00000039 20 salt_len + 0000003a 90 a4 54 9e 5a 0b salt + 00000040 56 70 e3 ce 68 ed 8e f6 b8 73 e7 93 b9 2d 91 9c + 00000050 a1 28 7d 8c b8 78 c2 74 81 d0 + 0000005a 53 4a 9e ff c6 d1 ed25519_sig + 00000060 d0 1d f2 c0 73 73 2f 05 28 aa 3d 1e 7d 85 a1 8f + 00000070 a5 de 5d ad 3c 85 ac 54 1f b8 b9 d0 c1 03 8d f1 + 00000080 6b 3d cd bc d4 1d 02 e5 f8 a2 18 de 0f 61 ce fa + 00000090 07 cb 40 db f6 63 b1 28 07 0b +``` + +## Inline signature + +```text +$ sq sign --signer-file alice.pgp message.txt +-----BEGIN PGP MESSAGE----- + +xEYGAAobIK+vlFDAK62+055LpOCoOGecp66NiyRz6M+emCLp5Nbg0Hsk7JGhTdJA +rC1T5sip4FSUmkEiLqc4V27RnK6j3JkByxJiAAAAAABoZWxsbyB3b3JsZArCmAYA +GwoAAAApBYJlPXuNIiEG0Hsk7JGhTdJArC1T5sip4FSUmkEiLqc4V27RnK6j3JkA +AAAAhrggr6+UUMArrb7Tnkuk4Kg4Z5ynro2LJHPoz56YIunk1uApSiAe9CYGgqrs +p6Ud6ARDVcOWWFhxTJK2rNULlZ9k4HPFvUT4PTrjpb4kjRAb6MDgSSclPaj14FjL +rpr/eqQF +=r993 +-----END PGP MESSAGE----- +``` + +```text +$ sq packet dump --hex inline-sig.txt +One-Pass Signature Packet, new CTB, 2 header bytes + 70 bytes + Version: 6 + Type: Binary + Pk algo: Ed25519 + Hash algo: SHA512 + Issuer: D07B24EC91A14DD240AC2D53E6C8A9E054949A41222EA738576ED19CAEA3DC99 + Last: true + + 00000000 c4 CTB + 00000001 46 length + 00000002 06 version + 00000003 00 type + 00000004 0a hash_algo + 00000005 1b pk_algo + 00000006 20 salt_len + 00000007 af af 94 50 c0 2b ad be d3 salt + 00000010 9e 4b a4 e0 a8 38 67 9c a7 ae 8d 8b 24 73 e8 cf + 00000020 9e 98 22 e9 e4 d6 e0 + 00000027 d0 7b 24 ec 91 a1 4d d2 40 issuer + 00000030 ac 2d 53 e6 c8 a9 e0 54 94 9a 41 22 2e a7 38 57 + 00000040 6e d1 9c ae a3 dc 99 + 00000047 01 last + +Literal Data Packet, new CTB, 2 header bytes + 18 bytes + Format: Binary data + Content: "hello world\n" + + 00000000 cb CTB + 00000001 12 length + 00000002 62 format + 00000003 00 filename_len + 00000004 00 00 00 00 date + 00000008 68 65 6c 6c 6f 20 77 6f hello wo + 00000010 72 6c 64 0a rld. + +Signature Packet, new CTB, 2 header bytes + 152 bytes + Version: 6 + Type: Binary + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-10-28 21:22:21 UTC (critical) + Issuer Fingerprint: D07B24EC91A14DD240AC2D53E6C8A9E054949A41222EA738576ED19CAEA3DC99 + Digest prefix: 86B8 + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 98 length + 00000002 06 version + 00000003 00 type + 00000004 1b pk_algo + 00000005 0a hash_algo + 00000006 00 00 00 29 hashed_area_len + 0000000a 05 subpacket length + 0000000b 82 subpacket tag + 0000000c 65 3d 7b 8d sig creation time + 00000010 22 subpacket length + 00000011 21 subpacket tag + 00000012 06 version + 00000013 d0 7b 24 ec 91 a1 4d d2 40 ac 2d 53 e6 issuer fp + 00000020 c8 a9 e0 54 94 9a 41 22 2e a7 38 57 6e d1 9c ae + 00000030 a3 dc 99 + 00000033 00 00 00 00 unhashed_area_len + 00000037 86 digest_prefix1 + 00000038 b8 digest_prefix2 + 00000039 20 salt_len + 0000003a af af 94 50 c0 2b salt + 00000040 ad be d3 9e 4b a4 e0 a8 38 67 9c a7 ae 8d 8b 24 + 00000050 73 e8 cf 9e 98 22 e9 e4 d6 e0 + 0000005a 29 4a 20 1e f4 26 ed25519_sig + 00000060 06 82 aa ec a7 a5 1d e8 04 43 55 c3 96 58 58 71 + 00000070 4c 92 b6 ac d5 0b 95 9f 64 e0 73 c5 bd 44 f8 3d + 00000080 3a e3 a5 be 24 8d 10 1b e8 c0 e0 49 27 25 3d a8 + 00000090 f5 e0 58 cb ae 9a ff 7a a4 05 +``` + +## Cleartext signature + +```text +$ sq sign --cleartext-signature --signer-file alice.pgp message.txt +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +hello world +-----BEGIN PGP SIGNATURE----- + +wpgGARsKAAAAKQWCZT0vBCIhBtB7JOyRoU3SQKwtU+bIqeBUlJpBIi6nOFdu0Zyu +o9yZAAAAANqgIHAzoRTzu/7Zuxc8Izf4r3/qSCmBfDqWzTXqmVtsSBSHACka3qbN +eehqu8H6S0UK8V7yHbpVhExu9Hu72jWEzU/B0h9MR5gDhJPoWurx8YfyXBDsRS4y +r13/eqMN8kfCDw== +=Ks9w +-----END PGP SIGNATURE----- +``` + +```text +$ sq packet dump --hex cleartext-sig.txt +Signature Packet, new CTB, 2 header bytes + 152 bytes + Version: 6 + Type: Text + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-10-28 15:55:48 UTC (critical) + Issuer Fingerprint: D07B24EC91A14DD240AC2D53E6C8A9E054949A41222EA738576ED19CAEA3DC99 + Digest prefix: DAA0 + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 98 length + 00000002 06 version + 00000003 01 type + 00000004 1b pk_algo + 00000005 0a hash_algo + 00000006 00 00 00 29 hashed_area_len + 0000000a 05 subpacket length + 0000000b 82 subpacket tag + 0000000c 65 3d 2f 04 sig creation time + 00000010 22 subpacket length + 00000011 21 subpacket tag + 00000012 06 version + 00000013 d0 7b 24 ec 91 a1 4d d2 40 ac 2d 53 e6 issuer fp + 00000020 c8 a9 e0 54 94 9a 41 22 2e a7 38 57 6e d1 9c ae + 00000030 a3 dc 99 + 00000033 00 00 00 00 unhashed_area_len + 00000037 da digest_prefix1 + 00000038 a0 digest_prefix2 + 00000039 20 salt_len + 0000003a 70 33 a1 14 f3 bb salt + 00000040 fe d9 bb 17 3c 23 37 f8 af 7f ea 48 29 81 7c 3a + 00000050 96 cd 35 ea 99 5b 6c 48 14 87 + 0000005a 00 29 1a de a6 cd ed25519_sig + 00000060 79 e8 6a bb c1 fa 4b 45 0a f1 5e f2 1d ba 55 84 + 00000070 4c 6e f4 7b bb da 35 84 cd 4f c1 d2 1f 4c 47 98 + 00000080 03 84 93 e8 5a ea f1 f1 87 f2 5c 10 ec 45 2e 32 + 00000090 af 5d ff 7a a3 0d f2 47 c2 0f +``` diff --git a/book/source/20-zoom_encyption.md b/book/source/20-zoom_encyption.md index afb9ae9..79880f2 100644 --- a/book/source/20-zoom_encyption.md +++ b/book/source/20-zoom_encyption.md @@ -1 +1,6 @@ + + # Zooming in: Packet structure of encrypted data diff --git a/book/source/21-resources.md b/book/source/21-resources.md index ce828cf..ada1327 100644 --- a/book/source/21-resources.md +++ b/book/source/21-resources.md @@ -1,3 +1,8 @@ + + # External resources [OpenPGP version 6 draft specification](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/) draft-ietf-openpgp-crypto-refresh [2023] @@ -8,7 +13,7 @@ ## Web of Trust [PGP Web of Trust: Core Concepts Behind Trusted Communication](https://www.linux.com/training-tutorials/pgp-web-trust-core-concepts-behind-trusted-communication/), -[PGP Web of Trust: Delegated Trust and Keyservers](https://web.archive.org/web/20210417113254/https://www.linuxfoundation.org/blog/pgp-web-of-trust-delegated-trust-and-keyservers/) [Konstantin Ryabitsev, 2014] +[PGP Web of Trust: Delegated Trust and Keyservers](https://www.linuxfoundation.org/blog/pgp-web-of-trust-delegated-trust-and-keyservers/) [Konstantin Ryabitsev, 2014] [OpenPGP Web of Trust](https://sequoia-pgp.gitlab.io/sequoia-wot/) [Neal Walfield, 2022]; implementation: . diff --git a/book/source/22-glossary.md b/book/source/22-glossary.md index 31d8674..3686526 100644 --- a/book/source/22-glossary.md +++ b/book/source/22-glossary.md @@ -1,3 +1,8 @@ + + # Glossary ```{glossary} diff --git a/book/source/23-acknowledgements.md b/book/source/23-acknowledgements.md index de67a3a..2c90fac 100644 --- a/book/source/23-acknowledgements.md +++ b/book/source/23-acknowledgements.md @@ -1 +1,6 @@ + + # Acknowledgements diff --git a/book/source/_static/.gitkeep b/book/source/_static/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/book/source/a-artifacts.md b/book/source/a-artifacts.md index 914a1d4..460a1b8 100644 --- a/book/source/a-artifacts.md +++ b/book/source/a-artifacts.md @@ -1,3 +1,8 @@ + + # Appendix A: OpenPGP artifacts (alice_priv)= diff --git a/book/source/conf.py b/book/source/conf.py index c734f9d..db227e5 100644 --- a/book/source/conf.py +++ b/book/source/conf.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 +# # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: @@ -7,7 +10,7 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'OpenPGP for application developers' -copyright = '2023, The "Notes on OpenPGP" project' +copyright = '2023, The "Notes on OpenPGP" project, CC-BY-SA-4.0' version = "0.01" # -- General configuration --------------------------------------------------- @@ -39,3 +42,7 @@ html_theme_options = { 'show_relbars': 'yes', 'show_powered_by': False, } + +# we want to circumvent obscure warnings about footnotes following a heading: +# https://github.com/executablebooks/MyST-Parser/issues/352 +myst_footnote_transition = False diff --git a/book/source/diag/OpenPGPCert_with_privatekeystore.png b/book/source/diag/OpenPGPCert_with_privatekeystore.png new file mode 100644 index 0000000..a15b169 Binary files /dev/null and b/book/source/diag/OpenPGPCert_with_privatekeystore.png differ diff --git a/book/source/diag/OpenPGPCert_with_privatekeystore.svg b/book/source/diag/OpenPGPCert_with_privatekeystore.svg new file mode 100644 index 0000000..0429f64 --- /dev/null +++ b/book/source/diag/OpenPGPCert_with_privatekeystore.svg @@ -0,0 +1,1413 @@ + +Transferable secret key singularComponent KeyD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99signing- key creation timeComponent KeyencryptionC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation timeOpenPGP CertificateComponent KeyD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99signing- key creation timeComponent KeyencryptionC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation timePrivate key store diff --git a/book/source/diag/TSK.png b/book/source/diag/TSK.png new file mode 100644 index 0000000..de7b024 Binary files /dev/null and b/book/source/diag/TSK.png differ diff --git a/book/source/diag/TSK.svg b/book/source/diag/TSK.svg new file mode 100644 index 0000000..0ae654e --- /dev/null +++ b/book/source/diag/TSK.svg @@ -0,0 +1,651 @@ + +Transferable secret keyComponent KeyD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99signing- key creation timeComponent KeyencryptionC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation time diff --git a/book/source/diag/asymmetric_keypair.png b/book/source/diag/asymmetric_keypair.png new file mode 100644 index 0000000..088b3c4 Binary files /dev/null and b/book/source/diag/asymmetric_keypair.png differ diff --git a/book/source/diag/asymmetric_keypair.svg b/book/source/diag/asymmetric_keypair.svg new file mode 100644 index 0000000..d7ef94a --- /dev/null +++ b/book/source/diag/asymmetric_keypair.svg @@ -0,0 +1,221 @@ + +Asymmetric keypairPublic KeyPrivate Key diff --git a/book/source/diag/certificate_packet_list.png b/book/source/diag/certificate_packet_list.png new file mode 100644 index 0000000..4202fdb Binary files /dev/null and b/book/source/diag/certificate_packet_list.png differ diff --git a/book/source/diag/certificate_packet_list.svg b/book/source/diag/certificate_packet_list.svg new file mode 100644 index 0000000..7c1fe73 --- /dev/null +++ b/book/source/diag/certificate_packet_list.svg @@ -0,0 +1,839 @@ + +Certificate packet listSignature packetSubkey binding signaturePublic-Subkey packetSignature packetSubkey binding signaturePublic-Subkey packetSignature packetSubkey binding signaturePublic-Subkey packetUser ID packet Signature packetCertifying self-signature for User IDSignature packetDirect Key SignaturePublic-Key packet diff --git a/book/source/diag/direct_key_signature_packet.png b/book/source/diag/direct_key_signature_packet.png new file mode 100644 index 0000000..6201954 Binary files /dev/null and b/book/source/diag/direct_key_signature_packet.png differ diff --git a/book/source/diag/passphrase_using_S2K.png b/book/source/diag/passphrase_using_S2K.png new file mode 100644 index 0000000..2607feb Binary files /dev/null and b/book/source/diag/passphrase_using_S2K.png differ diff --git a/book/source/diag/passphrase_using_S2K.svg b/book/source/diag/passphrase_using_S2K.svg new file mode 100644 index 0000000..c425b4f --- /dev/null +++ b/book/source/diag/passphrase_using_S2K.svg @@ -0,0 +1,326 @@ + +Protecting secret key material with a passphrase(string-to-key) S2K mechanismcorrect horse battery staplePassphrase diff --git a/book/source/diag/public-key_packet.png b/book/source/diag/public-key_packet.png new file mode 100644 index 0000000..bf42be8 Binary files /dev/null and b/book/source/diag/public-key_packet.png differ diff --git a/book/source/diag/public-key_packet.svg b/book/source/diag/public-key_packet.svg new file mode 100644 index 0000000..4de8301 --- /dev/null +++ b/book/source/diag/public-key_packet.svg @@ -0,0 +1,380 @@ + +Public-Key packetpublic key materialpk_algocreation_timeversion diff --git a/book/source/diag/public_key.png b/book/source/diag/public_key.png new file mode 100644 index 0000000..ff548d8 Binary files /dev/null and b/book/source/diag/public_key.png differ diff --git a/book/source/diag/public_key.svg b/book/source/diag/public_key.svg new file mode 100644 index 0000000..8bd2492 --- /dev/null +++ b/book/source/diag/public_key.svg @@ -0,0 +1,129 @@ + +Public part of an asymmetric keypairPublic Key diff --git a/book/source/diag/secret-key_packet.png b/book/source/diag/secret-key_packet.png new file mode 100644 index 0000000..d91128f Binary files /dev/null and b/book/source/diag/secret-key_packet.png differ diff --git a/book/source/diag/secret-key_packet.svg b/book/source/diag/secret-key_packet.svg new file mode 100644 index 0000000..a54cc1c --- /dev/null +++ b/book/source/diag/secret-key_packet.svg @@ -0,0 +1,474 @@ + +Secret-Key packetsecret key materials2k_usage (encryption information)public key materialpk_algocreation_timeversion diff --git a/book/source/diag/subkey_binding_signatur_for_signing_sk.png b/book/source/diag/subkey_binding_signatur_for_signing_sk.png new file mode 100644 index 0000000..d4cc751 Binary files /dev/null and b/book/source/diag/subkey_binding_signatur_for_signing_sk.png differ diff --git a/book/source/diag/subkey_binding_signatur_for_signing_sk.svg b/book/source/diag/subkey_binding_signatur_for_signing_sk.svg new file mode 100644 index 0000000..b995417 --- /dev/null +++ b/book/source/diag/subkey_binding_signatur_for_signing_sk.svg @@ -0,0 +1,991 @@ + +Subkey binding signature for signing subkeysPrimary key creates a subkey binding signature to bind the subkey to the primary keyComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation timeSubkey binding signature- signature creation time- key expiration time- key flags- issuer fingerprintSignature over:Primary keySubkeySignature metadata:- signature creation time- issuer fingerprintSignature over:Primary keySigning Subkey- Embedded signature: Primary key bindingSigning key creates a primary binding signature to associate the primary key to the subkeyComponent KeyD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99signing- key creation time diff --git a/book/source/diag/subkey_binding_signature.png b/book/source/diag/subkey_binding_signature.png new file mode 100644 index 0000000..0a68fd5 Binary files /dev/null and b/book/source/diag/subkey_binding_signature.png differ diff --git a/book/source/diag/subkey_binding_signature.svg b/book/source/diag/subkey_binding_signature.svg new file mode 100644 index 0000000..e42149c --- /dev/null +++ b/book/source/diag/subkey_binding_signature.svg @@ -0,0 +1,871 @@ + +C0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94FingerprintPrimary key creates a "subkey binding signature" to bind the subkey to the primary keySubkey binding signatureComponent KeyencryptionC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation timeSubkey binding signature- signature creation time- key expiration time- key flags- issuer fingerprintAdditional MetadataSignature over:- primary key- subkey diff --git a/book/source/diag/symmetric_key.png b/book/source/diag/symmetric_key.png new file mode 100644 index 0000000..42dc447 Binary files /dev/null and b/book/source/diag/symmetric_key.png differ diff --git a/book/source/diag/symmetric_key.svg b/book/source/diag/symmetric_key.svg new file mode 100644 index 0000000..8d556c9 --- /dev/null +++ b/book/source/diag/symmetric_key.svg @@ -0,0 +1,194 @@ + +Symmetric key diff --git a/book/source/diag/types_of_signatures.png b/book/source/diag/types_of_signatures.png new file mode 100644 index 0000000..8eef40d Binary files /dev/null and b/book/source/diag/types_of_signatures.png differ diff --git a/book/source/diag/user_id_certification.png b/book/source/diag/user_id_certification.png index 5f4c7e5..1765602 100644 Binary files a/book/source/diag/user_id_certification.png and b/book/source/diag/user_id_certification.png differ diff --git a/book/source/diag/user_id_certification.svg b/book/source/diag/user_id_certification.svg index 582ea0f..4911722 100644 --- a/book/source/diag/user_id_certification.svg +++ b/book/source/diag/user_id_certification.svg @@ -1,466 +1,726 @@ - - - - - - - - - - - - - - - - - - - - - - - - User ID binding signatureComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation timeKey metadata:- creation time,- ... - P - OpenPGP primary key(for certification) - - - - - - - Alice Adams <alice@example.org> - User ID - - - - - - - - - - - Primary key issues signature to associate the User ID with itself - - - This arrow is actually a shorthand for thecertification signature shown on the right - Signature Over:Primary Key,+ User ID+ Metadata associated with this Signature:- creation time- algorithm preferences- key expiration time- "Primary User ID" flag- primary key flags- primary key expiration time- ... - - - - + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;font-family:Sans;-inkscape-font-specification:'Sans, @wght=500';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 500;text-align:start;text-anchor:start;white-space:pre;inline-size:207.42;display:inline;fill:#3e4349;fill-opacity:1;stroke:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke" + x="1840.4709" + y="784.19983" + id="text11-2-8-02-9-0-9" + transform="matrix(0.98944431,0,0,1.0106683,1667.9245,664.09009)">Primary key creates a User ID binding signature to associate the User ID with the primary keyUser ID binding signature- signature creation time- key expiration time- primary User ID flag- algorithm preferences- key expiration time (primary key)- key flags (primary key)Signature over:Primary keyUser IDSignature metadata: diff --git a/book/source/index.md b/book/source/index.md index e56298d..23e7fcd 100644 --- a/book/source/index.md +++ b/book/source/index.md @@ -1,3 +1,8 @@ + + # OpenPGP for application developers **{sub-ref}`today`** diff --git a/book/source/mermaid/06-terminology.png b/book/source/mermaid/06-terminology.png new file mode 100644 index 0000000..1c6fa2b Binary files /dev/null and b/book/source/mermaid/06-terminology.png differ diff --git a/book/tmp/06-terminology.md b/book/tmp/06-terminology.md new file mode 100644 index 0000000..14b1a74 --- /dev/null +++ b/book/tmp/06-terminology.md @@ -0,0 +1,54 @@ + + +```{mermaid} +%%{ init: { 'flowchart': { 'curve': '' } } }%% +flowchart LR + signature(OpenPGP Signature) + 3rdcert(Third-Party Certification) + data(Data Signature) + selfcert(Self-Signature) + certification("Third-Party Certification + -------------------------------- + Self-Certification") + + signature --> data & selfcert & 3rdcert & confsig & standalone & timestamp + data --> binary & text + selfcert --> skbind & skrev + selfcert & 3rdcert --> certification + certification --> uidcert & uidrev & dksig & krev + subgraph Signature Types and Targets + standalone[0x02: Standalone] + subgraph Signature Packet + confsig[0x50: Third-Party Confirmation] + timestamp[0x40: Timestamp] + end + subgraph Data + binary[0x00: Binary Data] + text[0x01: Canonical Text] + end + subgraph Primary Key + User ID / Attr. Packet + uidcert[ + 0x10: Generic Certification + 0x11: Persona Certification + 0x12: Casual Certification + 0x13: Positive Certification + ] + uidrev[0x30: Certification Revocation] + end + subgraph Primary Key + dksig[0x1F: Direct-Key Signature] + krev[0x20: Key Revocation] + end + subgraph Primary + Subkey + skbind[ + 0x18: Subkey Binding + 0x19: Primary Key Binding + ] + skrev[0x28: Subkey Revocation] + end + end +``` +