diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..54fd6f2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +book/build diff --git a/.domains b/.domains new file mode 100644 index 0000000..9d4c460 --- /dev/null +++ b/.domains @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 +# +# See https://docs.codeberg.org/codeberg-pages/using-custom-domain/ for +# details. The first domain should be "main" the rest are aliases. + +openpgp.dev diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f964a01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +.idea +book/build/ +book/source/plain_svg diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..3d94d06 --- /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/assets/* book/source/img/* book/source/_static/epub/img/* book/source/_static/html/img/* +Copyright: 2023 The "Notes on OpenPGP" project +License: CC-BY-SA-4.0 + +Files: book/patches/*.patch book/source/examples/*.asc +Copyright: 2023 The "Notes on OpenPGP" project +License: CC0-1.0 diff --git a/.woodpecker/codespell.yml b/.woodpecker/codespell.yml new file mode 100644 index 0000000..45e9188 --- /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: main + 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 new file mode 100644 index 0000000..9254ebc --- /dev/null +++ b/.woodpecker/doc-pages.yml @@ -0,0 +1,58 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +steps: + pages: + image: woodpeckerci/plugin-docker-buildx + settings: + output: type=local,dest=public + # do not push, push cannot be used with output simultaneously anyway + dry_run: true + # do not refresh image + pull_image: false + purge: false + + pages-pr-preview: + image: bitnami/git + secrets: [ codeberg_token ] + commands: + - git config --global user.email heiko.schaefer+boiler@posteo.de + - git config --global user.name "Page Renderer" + - git clone -b pages https://$CODEBERG_TOKEN@codeberg.org/openpgp/pr-preview.git pr-preview + - rm -rf pr-preview/$CI_COMMIT_PULL_REQUEST + - cp -ar public/. pr-preview/$CI_COMMIT_PULL_REQUEST + - cd pr-preview + - > + if [ -z "$(git status --porcelain)" ]; then + echo "No changes" + else + git add . + git commit -m "Update rendered page" -m "Source: $CI_COMMIT_SHA" -m "See: $CI_BUILD_LINK" + git push + fi + when: + event: pull_request + + pages-publish: + image: bitnami/git + secrets: [ codeberg_token ] + commands: + - git config --global user.email heiko.schaefer+boiler@posteo.de + - git config --global user.name "Page Renderer" + - git clone -b pages https://$CODEBERG_TOKEN@codeberg.org/openpgp/site.git $CI_REPO_NAME + - cp -ar public/. $CI_REPO_NAME/book/ + # Needed for custom domains + - cp .domains $CI_REPO_NAME || true # Ignore if it doesn't exist + - cd $CI_REPO_NAME + - > + if [ -z "$(git status --porcelain)" ]; then + echo "No changes" + else + git add . + git commit -m "Update rendered page" -m "Source: $CI_COMMIT_SHA" -m "See: $CI_BUILD_LINK" + git push + fi + when: + event: push + # only do releases to the `site` repo for the "main" branch + branch: main diff --git a/.woodpecker/epub.yml b/.woodpecker/epub.yml new file mode 100644 index 0000000..f792022 --- /dev/null +++ b/.woodpecker/epub.yml @@ -0,0 +1,24 @@ +# 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: main + event: + - push + - pull_request + +steps: + epub-check: + image: archlinux:latest + commands: + - pacman -Sy --needed --noconfirm archlinux-keyring + - pacman -Syu --needed --noconfirm epubcheck inkscape noto-fonts make patch python-myst-parser python-sphinx python-sphinxext-opengraph ttf-montserrat + # fix sphinx: https://github.com/sphinx-doc/sphinx/issues/11598 + - patch -Np1 -d /usr/lib/python3.11/site-packages/ -i "$(pwd)/book/patches/sphinx-11766.patch" + - make -C book epub-check diff --git a/.woodpecker/licensing.yml b/.woodpecker/licensing.yml new file mode 100644 index 0000000..8779519 --- /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: main + 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..415b142 --- /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: main + event: + - push + - pull_request + +steps: + link-check: + image: archlinux:latest + commands: + - pacman -Sy --needed --noconfirm archlinux-keyring + - pacman -Syu --needed --noconfirm inkscape lychee make noto-fonts python-myst-parser python-sphinx python-sphinxext-opengraph ttf-montserrat + - make -C book html-linkcheck diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..223092b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,149 @@ + + +# Contributing + +These are the contribution guidelines for "Notes on OpenPGP." + +Development takes place at https://codeberg.org/openpgp/notes. + +Discussion around this project takes place in [`#notes-on-openpgp:matrix.org`] on [Matrix]. + +## Providing changes + +This project uses [sphinx] and [MyST-parser] to allow building various output formats, such as [HTML] and [EPUB], for the included book projects. + +Contributors can provide changes by pull request towards the project. + +### Requirements + +The following packages need to be installed on the system in order for the build to suceed: + +* [inkscape](https://inkscape.org) +* `make` +* [myst-parser](https://github.com/executablebooks/MyST-Parser) +* [sphinx](https://github.com/sphinx-doc/sphinx/) +* [sphinxext-opengraph](https://github.com/wpilibsuite/sphinxext-opengraph) + +Required fonts: + +* [Montserrat](https://github.com/JulietaUla/Montserrat) +* [Noto](https://fonts.google.com/noto) + +Optional test/check dependencies: + +* [codespell](https://github.com/codespell-project/codespell) +* [lychee](https://lychee.cli.rs/) +* [epubcheck](https://github.com/w3c/epubcheck) +* [watchexec](https://github.com/watchexec/watchexec) + +### Building and testing + +The included book projects can be built and tested using a `Makefile`. + +The below examples show how to use it with a book named `book`. + +To cleanly build the [HTML] output: + +```shell +$ make -C book clean build +``` + +To cleanly build the [EPUB] output: + +```shell +$ make -C book clean epub +``` + +To spell check all files using [codespell]: + +```shell +$ make -C book codespell +``` + +To check the external links in all [HTML] files using [lychee]: + +```shell +$ make -C book html-linkcheck +``` + +### Writing text + +The syntax follows what is available in [MyST-parser]. + +--- +**NOTE**: It is advisable to always relate to the [MyST-parser] documentation, as [MyST] itself offers more/ different features! + +--- + +#### Including files + +It is advisable to [include external files](https://myst-parser.readthedocs.io/en/latest/syntax/code_and_apis.html#including-code-from-files) with data, instead of using a code block to display the data. + +--- +**NOTE**: The reason for this is, that `codespell` is used to check for common spelling mistakes and output from other programs may contain text, that will trigger it to flag it as an error. + +To work around this issue, `codespell` is configured to ignore example files, so that not entire chapter files have to be ignored. + +--- + +Use the `{literalcode}` directive to include files: + +```` + +```{literalinclude} examples/my-example.txt +:language: text +``` + +```` + +#### Cross-referencing + +There are a few guidelines when it comes to cross-referencing, which work around oddities with [sphinx] and [MyST-parser]: + +* When adding [explicit targets], use [kebab case]. +* Do not rename already released [explicit targets], as it will break deep linking by downstreams relying on these targets. +* When referencing chapters by file, use `[](/my-chapter)`, instead of relying on [explicit targets] for a top-level heading. +* To reference a figure by its title, use `[](#my-figure)` for a figure with the `:name:` attribute `my-figure` (and e.g., the title `My Figure`). +* To reference a figure by number (e.g. `Fig. 1`), use ```{numref}`my-figure` ``` for a figure with the `:name:` attribute `my-figure`. + +#### Figures + +[Figure] environments must have a `:name:` attribute, prefixed with `fig-`, so that they can be referenced elsewhere. +The `:alt:` attribute should explain what is displayed in the picture, as this is an [accessibility] feature. To keep matters brief, components and symbols that are described in other figures already, can be referenced by name instead of explaining them in detail. + +#### Glossary + +This project defines terms in a [glossary]. Using the `term` role, it is possible to reference these terms from anywhere. +Given a term `My Term` in the glossary, it is possible to reference it directly using ```{term}`my term```` or indirectly ```{term}`something else````. + +There are a few rules, that should be kept in mind when creating terms and referencing them. + +* alternative terms for a term may exist in the glossary for completeness (e.g., `My Other Term` may point to `My Term` in the glossary) +* references to a term should always point to the deepest redirect (e.g., if `My Other Term` points to `My Term` in the glossary, references should point to `My Term` and not `My Other Term`) +* even if links to external resources can also be found in a section that is related to a term, the links related to the term should also be present in the glossary + +## License + +All text contributions fall under the terms of the [CC-BY-SA-4.0]. + +Configuration file contributions fall under the terms of the [CC0-1.0]. + +[`#notes-on-openpgp:matrix.org`]: https://matrix.to/#/%23notes-on-openpgp%3Amatrix.org +[Matrix]: https://matrix.org +[sphinx]: https://www.sphinx-doc.org/en/master/ +[MyST-parser]: https://myst-parser.readthedocs.io/en/latest/ +[HTML]: https://en.wikipedia.org/wiki/HTML +[EPUB]: https://en.wikipedia.org/wiki/EPUB +[MyST]: https://mystmd.org/guide/quickstart-myst-markdown +[codespell]: https://github.com/codespell-project/codespell +[lychee]: https://lychee.cli.rs +[explicit targets]: https://myst-parser.readthedocs.io/en/latest/syntax/cross-referencing.html#creating-explicit-targets +[kebab case]: https://en.wikipedia.org/wiki/Letter_case#Kebab_case +[Figure]: https://myst-parser.readthedocs.io/en/latest/syntax/images_and_figures.html#figures-images-with-captions +[accessibility]: https://en.wikipedia.org/wiki/Computer_accessibility +[glossary]: https://myst-parser.readthedocs.io/en/latest/syntax/typography.html#definition-lists-and-glossaries +[CC-BY-SA-4.0]: ./LICENSES/CC-BY-SA-4.0.txt +[CC0-1.0]: ./LICENSES/CC0-1.0.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..af41435 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +# SPDX-License-Identifier: CC0-1.0 + +FROM archlinux:latest AS build +COPY book/ /book +WORKDIR /book +# fix EPUB rendering: https://github.com/sphinx-doc/sphinx/issues/11598 +RUN \ + pacman -Sy --needed --noconfirm archlinux-keyring \ + && pacman -Syu --needed --noconfirm inkscape make noto-fonts patch python-myst-parser python-sphinx python-sphinxext-opengraph ttf-montserrat \ + && patch -Np1 -d /usr/lib/python3.11/site-packages/ -i /book/patches/sphinx-11766.patch \ + && make epub html + +FROM scratch +COPY --from=build /book/build/html / +COPY --from=build --chown=644 /book/build/epub/OpenPGP_for_application_developers.epub / 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 07010ad..740de1a 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,24 @@ SPDX-License-Identifier: CC-BY-SA-4.0 # Notes on OpenPGP The "Notes on OpenPGP" project aims to produce accessible documentation for the OpenPGP ecosystem. + +# OpenPGP for application developers + +A book for application developers who want to integrate OpenPGP functionality into their software. + +This book serves a standalone introduction to the concepts of OpenPGP. It also introduces readers to the [OpenPGP RFC](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/). + +## Rendered versions of this text + +### Stable + +The *main* branch of this repository is continuously built and deployed to: + +- html: +- epub: + +Note: This text is still under development. However, these links always present a stable view of our writing process. + +### Snapshots of work in progress + +The current state of pull requests is rendered to https://openpgp.codeberg.page/pr-preview/123456/ (you'll have to insert an actual pull request ID into the URL) diff --git a/book/.codespellrc b/book/.codespellrc new file mode 100644 index 0000000..280ba35 --- /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,./input,./assets/*/*,./source/examples/* diff --git a/book/Makefile b/book/Makefile new file mode 100644 index 0000000..6b598c1 --- /dev/null +++ b/book/Makefile @@ -0,0 +1,70 @@ +# 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. +CODESPELL ?= codespell +EBOOK_VIEWER ?= ebook-viewer +EPUBCHECK ?= epubcheck +INKSCAPE ?= inkscape +SPHINXOPTS ?= -W +SPHINXBUILD ?= sphinx-build +LYCHEE ?= lychee +PRINTF ?= printf +RM ?= rm +WATCHEXEC ?= watchexec +ASSETSDIR = assets +SOURCEDIR = source +BUILDDIR = build + +# clean build output and also preprocessed/ converted data +clean-all: clean + @$(RM) -rv $(SOURCEDIR)/plain_svg/ + +# convert all SVG to plain SVGs without metadata and paths instead of text +convert-svg: + for file in $(ASSETSDIR)/inkscape/*.svg $(ASSETSDIR)/drawio/*.svg; do if [[ ! -f $(SOURCEDIR)/plain_svg/$$(basename $$file) ]]; then $(INKSCAPE) --export-text-to-path --export-plain-svg --export-filename=$(SOURCEDIR)/plain_svg/$$(basename $$file) $$file; fi; done + +epub: convert-svg + @$(SPHINXBUILD) -M epub "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +epub-check: clean epub + @$(EPUBCHECK) "$(BUILDDIR)/epub/"*.epub + +# use watchexec to rebuild the EPUB whenever a markdown file changes +# this target kills *any* open instance of calibre's ebook-viewer, that is currently showing OpenPGPforapplicationdevelopers.epub +epub-watch: + @$(WATCHEXEC) --shell bash -e css,html,j2,md,py,svg 'make clean epub && ev_pid="$$(pgrep -af "^python3.*ebook-viewer.*OpenPGP_for_application_developers" | cut -f1 -d " ")" && if [[ -n "$$ev_pid" ]]; then kill -9 "$$ev_pid"; fi && $(EBOOK_VIEWER) $(BUILDDIR)/epub/OpenPGP_for_application_developers.epub &' + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +html: convert-svg + @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +html-linkcheck: clean html + @$(LYCHEE) --exclude "https://openpgp.dev*" --exclude "https://codeberg.org/openpgp/notes" "$(BUILDDIR)/html/"*.html + +# use watchexec to rebuild the HTML whenever a markdown file changes +html-watch: + @$(WATCHEXEC) --shell bash -e css,html,j2,md,py,svg 'make clean 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 + @$(CODESPELL) input/ || 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 +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/book/assets/drawio/PKESKv3-decryption.drawio b/book/assets/drawio/PKESKv3-decryption.drawio new file mode 100644 index 0000000..b6e37fe --- /dev/null +++ b/book/assets/drawio/PKESKv3-decryption.drawio @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/PKESKv3-decryption.svg b/book/assets/drawio/PKESKv3-decryption.svg new file mode 100644 index 0000000..da7e8d6 --- /dev/null +++ b/book/assets/drawio/PKESKv3-decryption.svg @@ -0,0 +1,4 @@ + + + +
Secret Key
Key-ID: 0xB0B
Secret KeyKey-ID: 0x...
Asymmetric
Decryption
Asymmetric...
Cipher Algorithm
+
Session Key
Cipher Algorithm...
PKESKv3
PKESKv3
Key-ID: 0xB0B
Key-ID: 0xB0B
Asymmetric Algo.
Asymmetric Algo.
ciphertext
ciphertext
Enc. Session-Key
Enc. Session-Key
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/PKESKv6-decryption.drawio b/book/assets/drawio/PKESKv6-decryption.drawio new file mode 100644 index 0000000..26142f7 --- /dev/null +++ b/book/assets/drawio/PKESKv6-decryption.drawio @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/PKESKv6-decryption.svg b/book/assets/drawio/PKESKv6-decryption.svg new file mode 100644 index 0000000..0a0dd87 --- /dev/null +++ b/book/assets/drawio/PKESKv6-decryption.svg @@ -0,0 +1,4 @@ + + + +
Secret Key
Key-ID: 0xB0B
Version: 6
Secret Key...
Asymmetric
Decryption
Asymmetric...
Session-Key
Session-Key
PKESKv6
PKESKv6
Fingerprint: 0xB0B
Fingerprint: 0xB...
Asymmetric Algo.
Asymmetric Algo.
ciphertext
ciphertext
Enc. Session-Key
Enc. Session-Key
Key-Version: 6
Key-Version: 6
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/SEIPDv1-PKESK.drawio b/book/assets/drawio/SEIPDv1-PKESK.drawio new file mode 100644 index 0000000..ff0732b --- /dev/null +++ b/book/assets/drawio/SEIPDv1-PKESK.drawio @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SEIPDv1-PKESK.svg b/book/assets/drawio/SEIPDv1-PKESK.svg new file mode 100644 index 0000000..95e1f2e --- /dev/null +++ b/book/assets/drawio/SEIPDv1-PKESK.svg @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + Session Key + + + + Session Key + + + + + + + + + PKESK #1 +0xBBBB... + + + + PKESK #10xBBBB... + + + + + + + + + PKESK #0 +0xAAAA... + + + + PKESK #00xAAAA... + + + + + + + + + + Alice' + Encryption Key + 0xAAAA... + + + + + + Alice'... + + + + + + + + + + Bob's + Encryption Key + 0xBBBB... + + + + + Bob's... + + + + + + + + + + + + + + + Plaintext + + + + Plaintext + + + + + + + + + SEIPDv1 + + + + SEIPDv1 + + + + + + + + + + + + Encrypted Message + + + + Encrypted Message + + + + diff --git a/book/assets/drawio/SEIPDv1-decryption.drawio b/book/assets/drawio/SEIPDv1-decryption.drawio new file mode 100644 index 0000000..adf2f4c --- /dev/null +++ b/book/assets/drawio/SEIPDv1-decryption.drawio @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SEIPDv1-decryption.svg b/book/assets/drawio/SEIPDv1-decryption.svg new file mode 100644 index 0000000..708593e --- /dev/null +++ b/book/assets/drawio/SEIPDv1-decryption.svg @@ -0,0 +1,4 @@ + + + +
key
key
Message-Key
(Session-Key)
Message-Key(Session-...
SEIPDv1
SEIPDv1
Encrypted Data
Encrypted Data
Symmetric
Decryption
Symmetric...
algorithm
algorithm
ciphertext
ciphertext
Plaintext
Plaintext
Cipher Algorithm
Cipher Algorithm
(obtained from PKESK / SKESK)
(obtained from PKESK / SKESK)
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/SEIPDv2-PKESK.drawio b/book/assets/drawio/SEIPDv2-PKESK.drawio new file mode 100644 index 0000000..9a4a400 --- /dev/null +++ b/book/assets/drawio/SEIPDv2-PKESK.drawio @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SEIPDv2-PKESK.svg b/book/assets/drawio/SEIPDv2-PKESK.svg new file mode 100644 index 0000000..12fea96 --- /dev/null +++ b/book/assets/drawio/SEIPDv2-PKESK.svg @@ -0,0 +1,583 @@ + + + + + + + + + + + + + + + Session Key + + + + Session Key + + + + + + + + + PKESK #1 +0xBBBB... + + + + PKESK #10xBBBB... + + + + + + + + + PKESK #0 +0xAAAA... + + + + PKESK #00xAAAA... + + + + + + + + + + Alice' + Encryption Key + 0xAAAA... + + + + + + Alice'... + + + + + + + + + + Bob's + Encryption Key + 0xBBBB... + + + + + + Bob's... + + + + + + + + + + + + + + + Plaintext + + + + Plaintext + + + + + + + + + Encrypted Message + + + + Encrypted Message + + + + + + + + + Message Key + + + + Message Key + + + + + + + + + + SEIPDv2 + + + + SEIPDv2 + + + + + + + + + Salt: 49f8edc3 + + + + Salt: 49f8edc3 + + + + + + + + + + + Ciphertext + + + + Ciphertext + + + + + + diff --git a/book/assets/drawio/SEIPDv2-decryption-chunks.drawio b/book/assets/drawio/SEIPDv2-decryption-chunks.drawio new file mode 100644 index 0000000..e38b132 --- /dev/null +++ b/book/assets/drawio/SEIPDv2-decryption-chunks.drawio @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SEIPDv2-decryption-chunks.svg b/book/assets/drawio/SEIPDv2-decryption-chunks.svg new file mode 100644 index 0000000..7376d21 --- /dev/null +++ b/book/assets/drawio/SEIPDv2-decryption-chunks.svg @@ -0,0 +1,4 @@ + + + +
key
key
key
key
Message-Key
Message-Key
SEIPDv2
SEIPDv2
Cipher Algo.
Cipher Algo.
AEAD Algo.
AEAD Algo.
Chunk Size
Chunk Size
Salt
Salt
Encrypted Data
Encrypted Data
ciphertext
ciphertext
Final AEAD
Auth Tag
Final AEAD...
IV
IV
AD
AD
Packet Type ID,
Version Number,
Cipher Algo,
AEAD Algo,
Chunk Size
Packet Type ID,...
Packet Type, Version
Packet Type, Version
+
+
toChunk(i)
toChunk(i)
append
chunk
index(i)
append...
Chunk #i
Chunk #i
nonce
nonce
nonce
nonce
Nonce #i
Nonce #i
ciphertext
ciphertext
Tag #i
Tag #i
AEAD
AEAD
Plaintext Block #i
Plaintext Block #i
Final
AEAD
Step
Final...
AD
AD
AD,
#Plaintext Octets
AD,...
AD
AD
""
""
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/SEIPDv2-decryption-mk-derivation.drawio b/book/assets/drawio/SEIPDv2-decryption-mk-derivation.drawio new file mode 100644 index 0000000..24dfd8d --- /dev/null +++ b/book/assets/drawio/SEIPDv2-decryption-mk-derivation.drawio @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SEIPDv2-decryption-mk-derivation.svg b/book/assets/drawio/SEIPDv2-decryption-mk-derivation.svg new file mode 100644 index 0000000..0619eda --- /dev/null +++ b/book/assets/drawio/SEIPDv2-decryption-mk-derivation.svg @@ -0,0 +1,4 @@ + + + +
Message-Key
Message-Key
SEIPDv2
SEIPDv2
Cipher Algo.
Cipher Algo.
AEAD Algo.
AEAD Algo.
Chunk Size
Chunk Size
salt
salt
Salt
Salt
Encrypted Data
Encrypted Data
Final AEAD
Auth Tag
Final AEAD...
IKM
IKM
Session-Key
Session-Key
HKDF
HKDF
IV
IV
info
info
Packet Type ID,
Version Number,
Cipher Algo,
AEAD Algo,
Chunk Size
Packet Type ID,...
Packet Type, Version
Packet Type, Version
+
+
(obtained from PKESK/SKESK)
(obtained from PKESK/SKESK)
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/SKESKv4-decryption.drawio b/book/assets/drawio/SKESKv4-decryption.drawio new file mode 100644 index 0000000..d7c71b5 --- /dev/null +++ b/book/assets/drawio/SKESKv4-decryption.drawio @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SKESKv4-decryption.svg b/book/assets/drawio/SKESKv4-decryption.svg new file mode 100644 index 0000000..c168a78 --- /dev/null +++ b/book/assets/drawio/SKESKv4-decryption.svg @@ -0,0 +1,4 @@ + + + +
Passphrase
Passphrase
S2K Function
S2K Function
Session Key
Session Key
Symmetric Key
Symmetric Key
SKESKv4
SKESKv4
Cipher Algo.
Cipher Algo.
S2K Identifier
S2K Identifier
ciphertext
ciphertext
Enc. Session-Key
Enc. Session-Key
yes
yes
key
key
no
no

Is
Encrypted
Session-Key
present
Is...
Symmetric
Decryption
Symmetric...
Cipher Algorithm
+
Session Key
Cipher Algorithm...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/SKESKv6-decryption.drawio b/book/assets/drawio/SKESKv6-decryption.drawio new file mode 100644 index 0000000..a9ec75b --- /dev/null +++ b/book/assets/drawio/SKESKv6-decryption.drawio @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/SKESKv6-decryption.svg b/book/assets/drawio/SKESKv6-decryption.svg new file mode 100644 index 0000000..02e79a2 --- /dev/null +++ b/book/assets/drawio/SKESKv6-decryption.svg @@ -0,0 +1,4 @@ + + + +
Encrypted Message
Encrypted Message
SEIPDv2
SEIPDv2
Salt: 49f8edc3
Salt: 49f8edc3
Ciphertext
Ciphertext
Cipher Algo.
Cipher Algo.
AEAD Mode
AEAD Mode
Chunk Size
Chunk Size
AEAD Auth Tag
AEAD Auth Tag
Passphrase
Passphrase
SKESKv6
SKESKv6
Cipher Algo.
Cipher Algo.
AEAD Mode
AEAD Mode
S2K Identifier
S2K Identifier
IV: 0xC0FFEE
IV: 0xC0FFEE
Enc. Session-Key
Enc. Session-Key
AEAD Auth Tag
AEAD Auth Tag
S2K Function
S2K Function
HKDF
(no salt)
HKDF(no salt)
IKM
IKM
Packet Type ID,
Packet Version,
Cipher Algo,
AEAD Mode
Packet Type ID,...
Packet Type and Version
Packet Type and Version
Key Encryption Key
Key Encryption Key
Info
Info
AEAD
AEAD
Packet Type ID,
Packet Version,
Cipher Algo,
AEAD Mode
Packet Type ID,...
Packet Type and Version
Packet Type and Version
Salt
Salt
AD
AD
Key
Key
Ciphertext
Ciphertext
Auth Tag
Auth Tag
Session Key
Session Key
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/attribute-shadowing.drawio b/book/assets/drawio/attribute-shadowing.drawio new file mode 100644 index 0000000..de3ad80 --- /dev/null +++ b/book/assets/drawio/attribute-shadowing.drawio @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/cert-validity-key-expiration.drawio b/book/assets/drawio/cert-validity-key-expiration.drawio new file mode 100644 index 0000000..0f63f6b --- /dev/null +++ b/book/assets/drawio/cert-validity-key-expiration.drawio @@ -0,0 +1 @@ +7ZtRc6I6FMc/jTO9D3YICSCPq213Z7x37p1x5u7uI4WoTCNxQ9za++lvIkGBREu3gKy2DxZP0JDf/yScc4gDOFltP7NgvfyLRpgMbCvaDuDdwLZHyBGv0vCSGRBEmWHB4igzgYNhFv+HldFS1k0c4bR0IqeU8HhdNoY0SXDIS7aAMfpcPm1OSbnXdbDAmmEWBkS3fo0jvlTDcqyD/QuOF8u8Z2CpllWQn6wM6TKI6HPBBO8HcMIo5dnRajvBRLLLuWSfezjSur8whhNe5wPf+Wj699SyLIfNsP/5+/Trty/DfBw/A7JRI1ZXy19yBIxukgjLb7EGcPy8jDmerYNQtj4LzYVtyVdEvAPiUH0dZhxvj14o2A9fuA2mK8zZizhFfQCpa1Ie46q3zwf83kjZlgX0KCcfKMkX+28+UBEHCsxbIL3OiMSJOBqnnNGnvaOIMY6jmAm3jGki3qd0I+0N4xqVcQFb5wUMuPaYG8fl9hqXbfWNl9drXtDuG69Rr3kh1Ddefq95OW7feIEa98QzAnN7t+ADoAHjloZMjJiXYWT0JpRQJiwJ3SGdx4RUTAGJF5JnKAhhYR9LfrGI0T6phlUcRbIbY3BSDl+a8FinzN/S+bsG/rA1/PY7/LVh36y4JtTReLaBDWiNDdRdE1yuawKvb76JdP66d14Mf9vvG389GOfwcvkj0Df+enDP0eXyd2Df+OvJAncul7/bt9jErRGbHCiA1+tLRQ0GNpyPQhyGmmCixdr9NYPVr4Q1yEDVN2B1W3NrU07nEr5LQH6W8Lo/NrLCOJ7ThA/TXX31kzgBWOvtDk7eLo4W8v/dVLTOMJkPZ8KDA75heCBDNukiWQ+P7F0d5F8jBr671rL1vZc/YTjI0i95Grfa7e1+u45Zob9hu91NsXTKaqcyoDX32uBE8/2HB9/XJlqE58GG5GNQ5Xsgp10UpMt9X93MQWBKe1ubg64e2raztC1YEMWC0l2htICDlJ9c9U7KQcU1xFySdBpaISEsy7PP6AryIKdLeWy9KNH6Egl+xyXS7naJlOlH92vksGVl2lhp83lfCTlrLwfH1+aOJny36zGs8VwgXQZreRhuGHkZsyB8wvx1gcpqkuARk39oGiv2BM95IfD/s9K8TwDyVIFlLI5nCoxy5bl3Q78puSqFIWhbtxBoihlrc60V52CNJxNXqxjye6gY0tO5fwWlSJPtYjJqUKkoQf/MGTXSw84LlwA6fZNA3xAyEQPMww58wVqg6n3k3Fp4pjD/4x6ilPCcW2iX4zTDdirTPUQoduvClkRzTVteWs7N7N8xN0NXUL76SM0aTs0cr5KajQxTvtPUDNUI9BdCmPXR0avtvcFjfrr1VioeArf2Lz4dcVoDU2Pv35u23xrDiqq3Ck9+UH+nnbbi/tlH6j9UOeELR2UaGnYzmeqGLWpSo47QvCavryBFMQ7rR2tCGLbuwE51yGfi9SQ6rqOFa2ePr92PqtqJ4gDsYY3G/aiqndigVa0l9EExT1/prqWeYFdn0LnXO0+vcN5U85Y/eqpHIZcYtSMPMjzl6VYefT/vTfbgVf2+LhVHTzu98CHPtC06z6oA1vVoVy2bIkNk3a12etk01w7n65yVUvGSyBdCkwVmJWGvS8BqrfX8AuqbiW+yytqJyXc9elU3X7aol3h7+OHwrq3w62t4/z8= \ No newline at end of file diff --git a/book/assets/drawio/cert-validity-simple.drawio b/book/assets/drawio/cert-validity-simple.drawio new file mode 100644 index 0000000..991fa94 --- /dev/null +++ b/book/assets/drawio/cert-validity-simple.drawio @@ -0,0 +1 @@ +5Vpdc6IwFP01PtohCR/yWLUfM92d3akzu9vHVKJmGo0TY9X99RskKBCs1IU2Q31wwoVAcs4Bzr2kgwbz7Z3Ay9l3HhHWgU607aBhB8IeCNV/HNglARe5SWAqaJSEwDEwon+JDjo6uqYRWeUOlJwzSZf54JgvFmQsczEsBN/kD5twlr/qEk+JERiNMTOjv2kkZ3pannOM3xM6naVXBo7eM8fpwTqwmuGIbzIhdNNBA8G5TFrz7YCwGLsUl6Tf7Ym9h4EJspBVOjzJ3sOPB8dxPDEi4d3Tw+8/9910Hq+YrfWM9WjlLoVA8PUiIvFZnA7qb2ZUktESj+O9G8W5is3knKktoJr6dERIsj05UHCYvpIN4XMixU4doju4ekxaMb7e3BzhD3o6NstADwMdxJry6eHMR1RUQwPzHpDOY8ToQrX6Kyn4y0Eoao79iAolS8oXanvF13G8Zrh6ebgANPECJXABvym4fKvhgo5teAVW44WgbXj1rMbLdW3DK7QaL8+3DS9Q4Z34iYD51j3wATAAk44BmZqxzIORoDfgjAsVWfA9pBPKWCGEGZ3GeI4VQkTF+zF+VHm0a71jTqMovkypOcnblzoU6+Xxd0z8/RL8UWPww//Qa83aLEgTmdAEsEybjWGDTGmC9koTBLZp0zXxN9XZGvxhaBv+phmXqL34u8A2/E1zL9324u8h2/A3kwXptRd/3zpvUpZ8+EzunfKrak7j5nBvmrsPJJ7KiLBJd6TQw3ItSCe2C/Hwkk7PIu2TRtSwMmcqOflAEJwY8mt1MulU7nizXVKR7Yqqj6IgsCPR4HwJLSszNfcwvL0NQ0OTEZngNZP16CYs+DbXlA3ySnTTWEqRmsS3dZMI5pG88nHCU91iAZeLBX6KWGKpNC2Wg1vfFbazCWhZBtqcWswE9JKnDKhPOO7Fwul+7kNmKnBElRAK77k0PMyUNwheyWaV5gXnn0uHd9eHKA2Z+YzBw2qGl3FzvBZs1xd4/ELkeULy7DH8TNhPvqIaa0YmMuMuvhV2H1xG6kdEgsVpOyK41KIbdsO6ss+C+4Ppdpausuy/sfQfVfgW8WXpKhayLKCrQmn/y9KFAuvoqvBl4cvS5Ya20eWWeepW0HXCtDToTPzAvUJB3pwE3pWPKnEMYe8qvZvrpxkaNP9S0EYG162peoBC1Q99dtXDNb86xEnqC2kxCRDZRoJp1Vt+HyDPNgrMlVP7dLfN94Eb2EaCmQM9ku7+VsCyzUz4yL+C58kAjveRbFTwzFMFxfIkAHqlK35OD3feC0zgFcoqFSV6uFT9qFRYA/euZailki3axH29NPm9XeIyiqzxz6ks0zeEcJKjbsmqnrIKfIOcVEjG6+fkfL0xS8Y7Pf0lRJQsYSmrOF7Cg9o8Lv/e78usoUc3/wA= \ No newline at end of file diff --git a/book/assets/drawio/cert-validity-subkey.drawio b/book/assets/drawio/cert-validity-subkey.drawio new file mode 100644 index 0000000..f241774 --- /dev/null +++ b/book/assets/drawio/cert-validity-subkey.drawio @@ -0,0 +1 @@ +7Vtbj+I2GP01SN0HVnGcEPI4MDO70rTqqkjd7qMhBqwxGBkzMP31dRIHkthAoAnjDcsDcr5csM85sb+L6cDhYveFo9X8DxZh2nGdaNeBjx3X7YNQfseG99TgQS81zDiJUhM4GEbkX6yMjrJuSITXhQsFY1SQVdE4YcslnoiCDXHOtsXLpowWf3WFZlgzjCaI6tbvJBJzNSzfOdi/YjKbZ78MHHVmgbKLlWE9RxHb5kzwqQOHnDGRtha7IaYxdhku6X3PR87uO8bxUlS54Yfov/z54jiOz0c4/PLj5fs/X7vZON4Q3agRq96K9wwCzjbLCMdPcTpwsJ0TgUcrNInPbiXn0jYXCyqPgGyqx2Eu8O5oR8F++FI2mC2w4O/yEiWRnurTNod3BuI8h7UHlREpjmf7Rx1gkA2FxCWonAeFkqVsDdaCs9e9MuSgBhHhUoeELeXxmm1ie134ZO+UGraCC7g6XsAAFwRNwdWzGi7XsQ2vwGq8oGsbXn2r8fI82/AKrcbL79mGF6iwCH4gYD3rJnwANMCEo0EmRyyKYKToDRllXFqWLIF0SigtmRAlsxjPiUQIS/sgxo9Ip+xBnViQKIp/xuiNFP2VOhTrF/F3dPx7Jvwbg9/9H3qtWZslaUIdmsDkuzUnTahLE7RXmiCwTZuejr+uztbg74a24a874wK2F38P2Ia/7twLr734+9A2/PVgQfjtxb9nnW9iCj56VCSe8ptszuLmY+I0d19wPJQRptPuSKKHxIbjTuwuxN1Lbxrz7J7MIruVe5Lh4UOOUeqQP8iHCafyjU+7FeH5W2H1XpQEdiAanM+Z5WUmxx6Gz89hqGkywlO0oaIe3YQlv83TZQN9g256TekmcxJP6yYVzF/4jU1SnuoWC7heLO6HiCWWStNi2Xvr76XjfABqikCbU4segF4zy4D6hONdLxz/lnPKjKOISN5Ly1pmfsxlMzBai2aF5Qfnp6HbCgvq4YvGw3qOVnFzsuH0fcDR5BWL84QU2aNojOk3tiYKa4qnIudM/F46vXcqMveDp1gc9z44E0pjj92wrmCz5OzBfvgZBhpjxni/sYAfVqg+3C1j5dSVHYxVyOffLWMwsJGxChWFu2XMCy1kzHM1xv6WKEUaba2JhEEpE+T5nomGmwbDnp6MHsoxqhDmFbeYDhdaSIfu3I0249ckPEi88jYTAn0LCdE32qj3o/V0eIF9dPgVgp+PqSu6gR4YBtC0ojaGjT6Vp3NHd0CWEVnOLsgtHM8iwJ8ki9BgTsDzS9T3deqhifrGcgL+L+/3OF2BjTkBrwJjMwn+6igAajsxGmeXOxcD44HP7pXFGb8xYCpsPbxou69x9S3nGJM0dfo5nWrUctvxx6ms1BNaOEpT17CZylT4aJCTCumQ+jk5n/fNk3HhDH8NEYadQ6ZZvjkefD1kPr3Cnyg7NVKNdO+lGmla8o1iaG7JN/0DQGPoGycLlIwjKTFV5PU3Z/fw8OlqLu2IgJpJVhdXy1BXQd80IzQmAlNlQaMznhTk5CCvy3IJJhpj0gef7onM4isNDctseFMydc8nP52P467HHFlKUQ2MlIr4+zjrw7INv8pAJ/IfwMKwKpOHKZ3dTcoLSLQ5Z+eH9uXsepV2wpSzqj+171EDk8FNi0Xy8PA33+Rc7r/S8Ok/ \ No newline at end of file diff --git a/book/assets/drawio/dk-attributes-and-shadowing.drawio b/book/assets/drawio/dk-attributes-and-shadowing.drawio new file mode 100644 index 0000000..e81cb62 --- /dev/null +++ b/book/assets/drawio/dk-attributes-and-shadowing.drawio @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/mdc.drawio b/book/assets/drawio/mdc.drawio new file mode 100644 index 0000000..353e8ba --- /dev/null +++ b/book/assets/drawio/mdc.drawio @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/drawio/mdc.svg b/book/assets/drawio/mdc.svg new file mode 100644 index 0000000..8abaf33 --- /dev/null +++ b/book/assets/drawio/mdc.svg @@ -0,0 +1,4 @@ + + + +
16 random bytes
16 random bytes
quick check bytes
quick...
Plaintext
Plaintext
0xD3
0x14
0xD3...
SHA1
Checksum
SHA1...
repeated 2 bytes
repeated 2 bytes
calculate / verify checksum
calculate / verify checksum
quick check
quick check
modification detection code
modification detection code
Text is not SVG - cannot display
\ No newline at end of file diff --git a/book/assets/drawio/narrow-interpretation.drawio b/book/assets/drawio/narrow-interpretation.drawio new file mode 100644 index 0000000..8a32531 --- /dev/null +++ b/book/assets/drawio/narrow-interpretation.drawio @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/inkscape/Binding_Subkeys.svg b/book/assets/inkscape/Binding_Subkeys.svg new file mode 100644 index 0000000..a874757 --- /dev/null +++ b/book/assets/inkscape/Binding_Subkeys.svg @@ -0,0 +1,779 @@ + +Binding SubkeysOpenPGP subkeysComponent 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/assets/inkscape/Binding_a_UserID.svg b/book/assets/inkscape/Binding_a_UserID.svg new file mode 100644 index 0000000..f882e6b --- /dev/null +++ b/book/assets/inkscape/Binding_a_UserID.svg @@ -0,0 +1,446 @@ + +- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certificationBinding a User ID diff --git a/book/assets/inkscape/Component_Key.svg b/book/assets/inkscape/Component_Key.svg new file mode 100644 index 0000000..ed3ffaf --- /dev/null +++ b/book/assets/inkscape/Component_Key.svg @@ -0,0 +1,266 @@ + +Component Key- key creation time diff --git a/book/assets/inkscape/Components_of_an_OpenPGP_Certificate.svg b/book/assets/inkscape/Components_of_an_OpenPGP_Certificate.svg new file mode 100644 index 0000000..0b48365 --- /dev/null +++ b/book/assets/inkscape/Components_of_an_OpenPGP_Certificate.svg @@ -0,0 +1,380 @@ + +Dr. Alice Adams<adams@work.example> diff --git a/book/assets/inkscape/Fingerprint.svg b/book/assets/inkscape/Fingerprint.svg new file mode 100644 index 0000000..8666887 --- /dev/null +++ b/book/assets/inkscape/Fingerprint.svg @@ -0,0 +1,350 @@ + +Fingerprint of an OpenPGP component key Component Key- key creation timeC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94Fingerprint diff --git a/book/assets/inkscape/Minimal_OpenPGP_certificate.svg b/book/assets/inkscape/Minimal_OpenPGP_certificate.svg new file mode 100644 index 0000000..845d9a2 --- /dev/null +++ b/book/assets/inkscape/Minimal_OpenPGP_certificate.svg @@ -0,0 +1,711 @@ + +Signature packet Direct Key Signature Cryptographic Signatureby the primary key over primary key, subkey and signature metadata Signature is created.Unhashed areaHashed areaFeaturesIssuer FingerprintKey FlagsPreferred Hash AlgorithmsPreferred Symmetric Ciphers for v1 SEIPDKey Expiration TimeSignature Creation TimeHash AlgorithmPublic-Key AlgorithmSignature typeVersionPublic-Key packetPublic Key MaterialPublic-Key AlgorithmCreation TimeVersionA minimal OpenPGP certificate diff --git a/book/assets/inkscape/OpenPGPCert_with_privatekeystore.svg b/book/assets/inkscape/OpenPGPCert_with_privatekeystore.svg new file mode 100644 index 0000000..ce51d7b --- /dev/null +++ b/book/assets/inkscape/OpenPGPCert_with_privatekeystore.svg @@ -0,0 +1,1302 @@ + +OpenPGP 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 time- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certificationDr. Alice Adams<adams@work.example>Private key store diff --git a/book/assets/inkscape/OpenPGP_Certificate.svg b/book/assets/inkscape/OpenPGP_Certificate.svg new file mode 100644 index 0000000..8c7d263 --- /dev/null +++ b/book/assets/inkscape/OpenPGP_Certificate.svg @@ -0,0 +1,1114 @@ + +OpenPGP 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 time- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certificationDr. Alice Adams<adams@work.example> diff --git a/book/assets/inkscape/OpenPGP_Signature_packet.svg b/book/assets/inkscape/OpenPGP_Signature_packet.svg new file mode 100644 index 0000000..54cde9f --- /dev/null +++ b/book/assets/inkscape/OpenPGP_Signature_packet.svg @@ -0,0 +1,288 @@ + +- signature type- additional metadataSignature metadataOpenPGP signature packetCryptographic signature diff --git a/book/assets/inkscape/OpenPGP_Signature_packet_2.svg b/book/assets/inkscape/OpenPGP_Signature_packet_2.svg new file mode 100644 index 0000000..46e481a --- /dev/null +++ b/book/assets/inkscape/OpenPGP_Signature_packet_2.svg @@ -0,0 +1,210 @@ + +OpenPGP signature packet - signature type- additional metadataSignature metadataSignature over:Input dataSignature diff --git a/book/assets/inkscape/Primary_key_metadata.svg b/book/assets/inkscape/Primary_key_metadata.svg new file mode 100644 index 0000000..cb4ba78 --- /dev/null +++ b/book/assets/inkscape/Primary_key_metadata.svg @@ -0,0 +1,433 @@ + +Primary key metadata- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certificationDirect key signature diff --git a/book/assets/inkscape/Signature_Creation.svg b/book/assets/inkscape/Signature_Creation.svg new file mode 100644 index 0000000..1c8f4d8 --- /dev/null +++ b/book/assets/inkscape/Signature_Creation.svg @@ -0,0 +1,794 @@ + +Signature creationComponent KeySigner private key- key creation timeA cryptographic signature is calculated over the hash digest, using the private key material of the signer.Signing mechanismhash digestA hash digest is calculated from the input data packets and the signature metadata.Signature typeSignature over:Input data packetsSignature metadata- ...This cryptographic signature is then stored in the signature packet.One or more packetsInput Data packetsHash mechanism diff --git a/book/assets/inkscape/Signature_Verification.svg b/book/assets/inkscape/Signature_Verification.svg new file mode 100644 index 0000000..30f6721 --- /dev/null +++ b/book/assets/inkscape/Signature_Verification.svg @@ -0,0 +1,825 @@ + +Signature verificationComponent KeySigner public key- key creation timeThe cryptographic signature is verified against the hash digest, using the public key of the signer.Signature verification mechanismhash digestA hash digest is calculated from the input data packets and the signature metadata.Signature typeSignature over:Input data packetsSignature metadata- ...One or more packetsInput Data packetsHash mechanism diff --git a/book/assets/inkscape/TSK.svg b/book/assets/inkscape/TSK.svg new file mode 100644 index 0000000..0ae654e --- /dev/null +++ b/book/assets/inkscape/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/assets/inkscape/asymmetric_keypair.svg b/book/assets/inkscape/asymmetric_keypair.svg new file mode 100644 index 0000000..d7ef94a --- /dev/null +++ b/book/assets/inkscape/asymmetric_keypair.svg @@ -0,0 +1,221 @@ + +Asymmetric keypairPublic KeyPrivate Key diff --git a/book/assets/inkscape/certificate_packet_list.svg b/book/assets/inkscape/certificate_packet_list.svg new file mode 100644 index 0000000..090f5ab --- /dev/null +++ b/book/assets/inkscape/certificate_packet_list.svg @@ -0,0 +1,603 @@ + +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/assets/inkscape/cryptographic_keypair.svg b/book/assets/inkscape/cryptographic_keypair.svg new file mode 100644 index 0000000..3ea075b --- /dev/null +++ b/book/assets/inkscape/cryptographic_keypair.svg @@ -0,0 +1,162 @@ + +Cryptographic keypairPublic KeyPrivate Key diff --git a/book/assets/inkscape/cryptographic_signature.svg b/book/assets/inkscape/cryptographic_signature.svg new file mode 100644 index 0000000..0b1c7c7 --- /dev/null +++ b/book/assets/inkscape/cryptographic_signature.svg @@ -0,0 +1,137 @@ + +Cryptographic signature diff --git a/book/assets/inkscape/diag_library_draft.svg b/book/assets/inkscape/diag_library_draft.svg new file mode 100644 index 0000000..2be10cb --- /dev/null +++ b/book/assets/inkscape/diag_library_draft.svg @@ -0,0 +1,4013 @@ + +Peach red#EB5937Dark slategray#195962Pyrite yellow#baa600Sea green#18A589Dark Slate Grey#3e4349Teal#006961OpenPGP Certificate- key creation timeComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certificationComponent Key- key creation timeD07B 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 CA94AliceUser IDAlice Adams <alice@example.org>User IDCryptographic keypairPublic KeyPrivate KeyFingerprint of an OpenPGP component key - key creation timeComponent KeyC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94FingerprintSubkeys- key creation timeComponent Key AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certificationComponent Key- key creation timeD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99- key creation timeComponent KeyC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94authentisigningComponent Key- key creation timeD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99signing- key creation timeComponent KeyC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94encryptionOpenPGP subkeysOpenPGP primary key- key creation timeComponent Key diff --git a/book/assets/inkscape/direct_key_signature_packet.svg b/book/assets/inkscape/direct_key_signature_packet.svg new file mode 100644 index 0000000..f1731d4 --- /dev/null +++ b/book/assets/inkscape/direct_key_signature_packet.svg @@ -0,0 +1,486 @@ + +Signature packet Direct Key Signature Cryptographic Signatureby the primary key over primary key, subkey and signature metadata Unhashed areaHashed areaFeaturesIssuer FingerprintKey FlagsPreferred Hash AlgorithmsPreferred Symmetric Ciphers for v1 SEIPDKey Expiration TimeSignature Creation TimeHash AlgorithmPublic-Key AlgorithmSignature TypeVersion diff --git a/book/assets/inkscape/id_card.svg b/book/assets/inkscape/id_card.svg new file mode 100644 index 0000000..5cbf1b3 --- /dev/null +++ b/book/assets/inkscape/id_card.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/assets/inkscape/meaning_of_signatures.svg b/book/assets/inkscape/meaning_of_signatures.svg new file mode 100644 index 0000000..10b44fc --- /dev/null +++ b/book/assets/inkscape/meaning_of_signatures.svg @@ -0,0 +1,466 @@ + +Signature typeSignature over:Signature dataSignature metadataCryptographic signatureOpenPGP signature packet- signature type- signature over input data- additional metadata- cryptographic signatureMeanings of signature in OpenPGP diff --git a/book/assets/inkscape/passphrase_using_S2K.svg b/book/assets/inkscape/passphrase_using_S2K.svg new file mode 100644 index 0000000..dde4212 --- /dev/null +++ b/book/assets/inkscape/passphrase_using_S2K.svg @@ -0,0 +1,328 @@ + +Converting a passphrase into a symmetric key(string-to-key) S2K mechanismcorrect horse battery staplePassphrase diff --git a/book/assets/inkscape/public-key_packet.svg b/book/assets/inkscape/public-key_packet.svg new file mode 100644 index 0000000..1582837 --- /dev/null +++ b/book/assets/inkscape/public-key_packet.svg @@ -0,0 +1,381 @@ + +Public-Key packetPublic Key MaterialPublic-Key AlgorithmCreation TimeVersion diff --git a/book/assets/inkscape/public_key.svg b/book/assets/inkscape/public_key.svg new file mode 100644 index 0000000..8bd2492 --- /dev/null +++ b/book/assets/inkscape/public_key.svg @@ -0,0 +1,129 @@ + +Public part of an asymmetric keypairPublic Key diff --git a/book/assets/inkscape/secret-key_packet.svg b/book/assets/inkscape/secret-key_packet.svg new file mode 100644 index 0000000..2806631 --- /dev/null +++ b/book/assets/inkscape/secret-key_packet.svg @@ -0,0 +1,475 @@ + +Secret-Key packetSecret Key MaterialS2K Usage (Secret Key Encryption)Public Key MaterialPublic-Key AlgorithmCreation TimeVersion diff --git a/book/assets/inkscape/subkey_binding_signatur_for_signing_sk.svg b/book/assets/inkscape/subkey_binding_signatur_for_signing_sk.svg new file mode 100644 index 0000000..4cf8445 --- /dev/null +++ b/book/assets/inkscape/subkey_binding_signatur_for_signing_sk.svg @@ -0,0 +1,1052 @@ + +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 itself with the primary keyComponent KeyD07B 24EC 91A1 4DD2 40AC 2D53 E6C8 A9E0 5494 9A41 222E A738 576E D19C AEA3 DC99signing- key creation timeThe "Notes on OpenPGP" projecthttps://codeberg.org/openpgp/notes/ diff --git a/book/assets/inkscape/subkey_binding_signature.svg b/book/assets/inkscape/subkey_binding_signature.svg new file mode 100644 index 0000000..6a93c64 --- /dev/null +++ b/book/assets/inkscape/subkey_binding_signature.svg @@ -0,0 +1,894 @@ + +Subkey binding signatureComponent KeyencryptionC0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94- key creation timePrimary 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:The "Notes on OpenPGP" projecthttps://codeberg.org/openpgp/notes/ diff --git a/book/assets/inkscape/symmetric_key.svg b/book/assets/inkscape/symmetric_key.svg new file mode 100644 index 0000000..52b04de --- /dev/null +++ b/book/assets/inkscape/symmetric_key.svg @@ -0,0 +1,116 @@ + +Symmetric key diff --git a/book/assets/inkscape/user_id_certification.svg b/book/assets/inkscape/user_id_certification.svg new file mode 100644 index 0000000..191e680 --- /dev/null +++ b/book/assets/inkscape/user_id_certification.svg @@ -0,0 +1,776 @@ + +User ID binding signatureComponent Key (primary)AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3certification- key creation timePrimary key creates a User ID binding signature to associate the User ID with the primary keyUser ID binding signature- signature creation time- primary User ID flag- algorithm preferences- key expiration time (primary key)- key flags (primary key)Signature over:Primary keyUser IDSignature metadata:The "Notes on OpenPGP" projecthttps://codeberg.org/openpgp/notes/ diff --git a/book/assets/inkscape/with_subkeys.svg b/book/assets/inkscape/with_subkeys.svg new file mode 100644 index 0000000..21d9ba6 --- /dev/null +++ b/book/assets/inkscape/with_subkeys.svg @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + Key creation time + OpenPGP primary key(for certification) + + + + Key creation time + OpenPGP subkey(for encryption) + + + + Key creation time + OpenPGP subkey(for signing) + + + + + P + + diff --git a/book/assets/mermaid/09-sigtree.md b/book/assets/mermaid/09-sigtree.md new file mode 100644 index 0000000..2ef16cd --- /dev/null +++ b/book/assets/mermaid/09-sigtree.md @@ -0,0 +1,23 @@ +```{mermaid} +flowchart TD + subgraph Certificate + pk["Primary Key"] + uid["#quot;Alice #lt;alice@example.org#gt;#quot;"] + sk["Signing Subkey"] + + usig(["PositiveCertification + PrimaryUserID: true"]) + dksig(["DirectKeySignature"]) + sksig(["SubkeyBindingSignature + KeyFlags: Sign Data + EmbeddedSignature: BackSignature"]) + pk --- usig --> uid + dksig --> pk --- dksig + pk --- sksig --> sk + end + + ds(["Data Signature"]) + data("Data") + + sk --- ds --> data +``` \ No newline at end of file diff --git a/book/assets/mermaid/sig-types.md b/book/assets/mermaid/sig-types.md new file mode 100644 index 0000000..0e94335 --- /dev/null +++ b/book/assets/mermaid/sig-types.md @@ -0,0 +1,56 @@ + + +```{mermaid} +%%{ init: { 'flowchart': { 'curve': 'monotoneX' } } }%% +flowchart LR + signature(OpenPGP Signature) + + data(Signature on Data) + + sigcomp(Signature on Component) + selfsig(Self-Signature) + thirdparty(Third-Party) + + signature --> confsig & standalone & timestamp & data & sigcomp + + data --> binary & text + + sigcomp --> selfsig & thirdparty + selfsig --> skbind & skrev & uidcert & uidrev & dksig & krev + thirdparty --> uidcert & uidrev & dksig + + 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 +``` diff --git a/book/patches/sphinx-11766.patch b/book/patches/sphinx-11766.patch new file mode 100644 index 0000000..c507523 --- /dev/null +++ b/book/patches/sphinx-11766.patch @@ -0,0 +1,26 @@ +diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py +index 85067be0178..91d3647597c 100644 +--- a/sphinx/builders/html/__init__.py ++++ b/sphinx/builders/html/__init__.py +@@ -1061,7 +1061,9 @@ def css_tag(css: _CascadingStyleSheet) -> str: + attrs.append(f'{key}="{html.escape(value, quote=True)}"') + uri = pathto(os.fspath(css.filename), resource=True) + if checksum := _file_checksum(outdir, css.filename): +- uri += f'?v={checksum}' ++ # the EPUB format does not allow the use of query components ++ if self.name != 'epub': ++ uri += f'?v={checksum}' + return f'' + + ctx['css_tag'] = css_tag +@@ -1092,7 +1094,9 @@ def js_tag(js: _JavaScript | str) -> str: + # https://github.com/sphinx-doc/sphinx/issues/11658 + pass + elif checksum := _file_checksum(outdir, js.filename): +- uri += f'?v={checksum}' ++ # the EPUB format does not allow the use of query components ++ if self.name != 'epub': ++ uri += f'?v={checksum}' + if attrs: + return f'' + return f'' diff --git a/book/source/_static/.gitkeep b/book/source/_static/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/book/source/_static/epub/css/custom.css b/book/source/_static/epub/css/custom.css new file mode 100644 index 0000000..22877d3 --- /dev/null +++ b/book/source/_static/epub/css/custom.css @@ -0,0 +1,74 @@ +/* +SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +SPDX-License-Identifier: CC0-1.0 +*/ + +/* +Admonitions +*/ +div.admonition { + background-color: lightgray; +} + +div.warning, +div.admonition-warning { + background-color: palevioletred; +} + +/* +External links +*/ +a.external.reference { + border-bottom: 1px solid darkgreen; + color: darkgreen; + text-decoration: none; +} + +/* +Internal links +*/ +a.internal { + text-decoration: none; + border-bottom-style: none; +} + +/* +Text in section and reference links and footnote links +*/ +span.std-doc, +span.std-numref, +span.std-ref, +a.footnote-reference { + border-bottom: 1px dashed #3333ff; + color: #3333ff; + text-decoration: none; +} + +/* +Text in glossary links +*/ +span.std-term { + color: black; + border-bottom: 1px dotted black; +} + +/* +Footnote list +*/ +aside.footnote-list { + border-top: 1px solid black; + margin-top: 2em; + padding-top: 2em; +} + +/* +Cover +*/ + +div.cover-img { + text-align: center; +} + +div.cover-img span img { + height: 100%; +} \ No newline at end of file diff --git a/book/source/_static/epub/img/cover.png b/book/source/_static/epub/img/cover.png new file mode 100644 index 0000000..8c341da Binary files /dev/null and b/book/source/_static/epub/img/cover.png differ diff --git a/book/source/_static/html/css/custom.css b/book/source/_static/html/css/custom.css new file mode 100644 index 0000000..ec0eaff --- /dev/null +++ b/book/source/_static/html/css/custom.css @@ -0,0 +1,57 @@ +/* +SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +SPDX-License-Identifier: CC0-1.0 + +NOTE: Colors are adapted to match those of the "alabaster" theme +*/ + +/* +External links +*/ +a.external.reference { + color: darkgreen; + text-decoration: none; + border-bottom: 1px solid darkgreen; +} + +/* +Internal links +*/ +a.internal.reference { + text-decoration: none; + border-bottom-style: none; +} + +/* +Text in section and reference links +*/ +span.std-doc, +span.std-numref, +span.std-ref, +a.footnote-reference { + border-bottom: 1px dashed #3333ff; + color: #3333ff; + text-decoration: none; +} + +a.footnote-reference:hover { + border-bottom: 1px dashed #3333ff; + text-decoration: none; +} + +/* +Text in glossary links +*/ +span.std-term { + color: rgb(62, 67, 73); + border-bottom: 1px dotted rgb(62, 67, 73); +} + +/* +Footnote list +*/ +aside.footnote-list { + border-top: 1px solid black; + margin-top: 2em; + padding-top: 2em; +} \ No newline at end of file diff --git a/book/source/_static/html/img/favicon.ico b/book/source/_static/html/img/favicon.ico new file mode 100644 index 0000000..27ffc73 Binary files /dev/null and b/book/source/_static/html/img/favicon.ico differ diff --git a/book/source/_static/html/img/favicon.svg b/book/source/_static/html/img/favicon.svg new file mode 100644 index 0000000..c12de0b --- /dev/null +++ b/book/source/_static/html/img/favicon.svg @@ -0,0 +1,158 @@ + + diff --git a/book/source/_static/html/img/logo.png b/book/source/_static/html/img/logo.png new file mode 100644 index 0000000..4d3a395 Binary files /dev/null and b/book/source/_static/html/img/logo.png differ diff --git a/book/source/_static/html/img/logo.svg b/book/source/_static/html/img/logo.svg new file mode 100644 index 0000000..b888225 --- /dev/null +++ b/book/source/_static/html/img/logo.svg @@ -0,0 +1,137 @@ + + diff --git a/book/source/_templates/cover.j2 b/book/source/_templates/cover.j2 new file mode 100644 index 0000000..7f4b19b --- /dev/null +++ b/book/source/_templates/cover.j2 @@ -0,0 +1,22 @@ +{# +SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project +SPDX-License-Identifier: CC-BY-SA-4.0 +#} +{%- extends "layout.html" %} +{%- block header %}{% endblock %} +{%- block rootrellink %}{% endblock %} +{%- block relbaritems %}{% endblock %} +{%- block sidebarlogo %}{% endblock %} +{%- block linktags %}{% endblock %} +{%- block relbar1 %}{% endblock %} +{%- block sidebar1 %}{% endblock %} +{%- block sidebar2 %}{% endblock %} +{%- block footer %}{% endblock %} + +{% block content %} +
+ + Cover + +
+{% endblock %} diff --git a/book/source/about.md b/book/source/about.md new file mode 100644 index 0000000..07ea24c --- /dev/null +++ b/book/source/about.md @@ -0,0 +1,51 @@ + + +# Introducing OpenPGP + +This documentation project is designed to provide a comprehensive understanding of OpenPGP, highlighting its functionalities and applications for software developers. While this document predominantly references [OpenPGP version 6, as outlined in the latest RFC](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/), it is important to note that the fundamental principles and functionalities of OpenPGP have remained consistent across its versions since its first release as an open standard in RFC 2440 in 1998. + +This documentation project seeks to introduce all OpenPGP concepts and functionalities to application developers who wish to use it in their projects. + +## What is OpenPGP? + +OpenPGP is an open standard for cryptographic operations. It is a system based on well-understood [cryptographic building blocks](/cryptography). OpenPGP supports the secure delivery of files and messages between a sender and a recipient. It also addresses identities and their verification. OpenPGP is an outgrowth of the ["Pretty Good Privacy (PGP)"](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) encryption program and has many widely used and [interoperable implementations](interoperability). + +With OpenPGP, you can: + +- [Encrypt](/encryption) and [decrypt](/decryption) messages to preserve confidentiality +- [Sign](/signing_data) and [verify](/verification) data to ensure {term}`authenticity` +- [Issue and validate certifications](/signing_components) about {term}`keys` and {term}`identities`, similar to the role of a {term}`Certificate Authority` ({term}`CA`) in validating {term}`identities`. + +## Who is the audience for this document? + +Three groups of people interact with OpenPGP: + +1. End-users, who use software that contains OpenPGP functionality (e.g., the Thunderbird email software) +2. Software developers who build applications that contain OpenPGP functionality +3. Implementers of OpenPGP libraries (or other software that directly handles the processing of internal OpenPGP data structures) + +This document is not intended for end-users or implementers of OpenPGP libraries (or other software that directly handles internal OpenPGP data structures). + +Instead, this document is focused on the second group, application developers, who use OpenPGP functionality in their software projects. It describes the properties of the OpenPGP system and its uses. It presupposes solid knowledge of software development concepts and of general cryptographic concepts. Thus, this text describes OpenPGP at the "library-level," teaching concepts that will help software developers get started as a user of any implementation (e.g., [OpenPGP.js](https://openpgpjs.org/), [Sequoia-PGP](https://sequoia-pgp.org/)). + +With the emergence of a new crop of modern, high-quality OpenPGP libraries, and the imminent release of the updated [OpenPGP version 6 specification](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/), we think that now is a great time to implement OpenPGP functionality in applications or to modernize existing OpenPGP subsystems. + +The goal of this document is to offer an implementation-independent introduction to the OpenPGP technology, assisting software developers in quickly familiarizing themselves and serving as a pathway to relevant information in the RFC. + +## Why not just use the OpenPGP RFC? + +The [OpenPGP RFC](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/) +defines *the message formats used in OpenPGP.* That is, it describes the internal structure of OpenPGP data, which is crucial for OpenPGP library implementers. However, this level of detail is not required for software developers who use OpenPGP via a library. + +This document describes OpenPGP concepts at the "library" level of abstraction, omitting unnecessary detail about the internal encoding of OpenPGP artifacts. Instead, we focus on the properties of these OpenPGP artifacts and how they are used, while adding context that is not elaborated on in the [RFC](https://en.wikipedia.org/wiki/Request_for_Comments). + +## Which version of OpenPGP does this address? + +This documentation encompasses the core aspects of modern OpenPGP practices, applicable across different versions. This respects that, at a foundational level, there is significant overlap, continuity, and consistency from its earliest version to its latest. + +While using version 6 as a reference for current standards, we include insights derived from earlier versions, particularly version 4, which continues to be widely used in ongoing projects. + +Where differences between OpenPGP versions are relevant to application development, we provide focused insights to ensure the content remains as version-agnostic as possible and, thus, broadly applicable for developers working with various iterations of OpenPGP. diff --git a/book/source/acknowledgements.md b/book/source/acknowledgements.md new file mode 100644 index 0000000..fe02025 --- /dev/null +++ b/book/source/acknowledgements.md @@ -0,0 +1,57 @@ + + +# Acknowledgements + +OpenPGP is a manifestation of [the political vision of Phil Zimmermann](https://philzimmermann.com/EN/background/peace.html), reflecting his commitment to human rights and the peace movement. Therefore, we foremost acknowledge Phil, who, alongside early PGP developers, worked with dedication and courage to introduce one of the first sophisticated cryptographic tools to the world, despite substantial personal risk. + +All subsequent projects in the OpenPGP space are indebted to the foundational ideas and principles of those early days[^puzzle], including the pivotal decision to standardize the OpenPGP format through the IETF. + +[^puzzle]: These ideas and principles include some ongoing challenges, such as the puzzle of how to develop a scalable distributed PKI and trust model. + +In the intervening three decades, many have contributed to the OpenPGP space. We recognize the civic-oriented work of those who have helped evolve the OpenPGP ecosystem into a tool for digital empowerment. + +## Team + +The "Notes on OpenPGP" project is a collective endeavor, with contributions from a wide-ranging community. + +The principal authors of this work, "OpenPGP for application developers," are: + +- Tammi Coles (editor) +- Sabrina Kurtz (illustrator) +- Wiktor Kwapisiewicz +- David Runge +- Paul Schaub +- Heiko Schäfer + +## Expert advisors, readers, supporters + +Andrew Gallagher provided input and discussions, particularly regarding the SKS Keyserver network. + +Daniel Huigens was instrumental in shaping the early direction of this project. + +Daniel Kahn Gillmor provided valuable input and encouragement. + +Dennis Schmolk thoroughly reviewed the initial draft, offering detailed critiques. + +Lance Vick contributed strategic communication advice. + +Lars Wirzenius provided extensive feedback on early drafts. + +Levente Polyak shared insights from the vantage point of an organization extensively using OpenPGP and developing custom OpenPGP applications. + +Ryan Heywood gave early feedback on our binding signature visualizations. + +## Extended hat tips + +Werner Koch for his enduring work on [GnuPG](https://gnupg.org/) and for fostering an interoperable ecosystem. + +[Sequoia-PGP](https://sequoia-pgp.org/), for bringing OpenPGP to the Rust language and developing an essential interoperability test suite. + +ProtonMail for maintaining two crucial modern implementations of OpenPGP: [OpenPGP.js](https://openpgpjs.org/) and [GopenPGP](https://gopenpgp.org/). + +## Funding + +The [Sovereign Tech Fund](https://sovereigntechfund.de/) commissioned the initial development of this project from September to December 2023. We are extremely grateful for their support. diff --git a/book/source/adv/certificates.md b/book/source/adv/certificates.md new file mode 100644 index 0000000..c6db1ba --- /dev/null +++ b/book/source/adv/certificates.md @@ -0,0 +1,381 @@ + + +# Advanced material: Certificates + +## When are certificates valid? + +Certificates are composites of components that are linked together using [signatures](../signing_components). + +A certificate can be valid or invalid as a whole. However, even when a certificate is valid, individual components (subkeys or identities) of it can be invalid. + +In this section, we discuss the validity of certificates and their components. This discussion is closely related to [signature validity](/verification), and builds on that concept. + +The validity of the signatures that link a certificate is a necessary precondition. Two concepts are particularly central to the validity of certificates and components: + +- Expiration +- Revocation + +### Expiration + +Certificates and components can "expire," which renders them invalid. Each component of a certificate can have an expiration time, or be unlimited in its temporal validity. + +The OpenPGP software of a sender will refuse to encrypt email using an expired certificate, or using an encryption component key that is expired. The sender's software rejects encryption to the key, essentially as a courtesy to the certificate owner, respecting the preferences expressed in their certificate metadata. + +The expiration mechanism in OpenPGP is complemented by a mechanism to extend/renew expiration time. + +Using the expiration mechanism is useful for two reasons: + +- Expiration of a certificate means that it cannot be used anymore. This forces users of that certificate (or their OpenPGP software) to poll for updates for it. For example, from a keyserver. +- It is a passive way for certificates to "time out," e.g., if their owner loses control over them, or isn't able to broadcast a revocation, for any reason. + +Component keys use *Key Expiration Time* subpackets for expressing the expiration time. Identity components rely on the [*signature expiration time*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#signature-expiration-subpacket) subpacket of their binding signature. If a binding signature expires, the binding becomes invalid, and the component is considered expired. + +### Revocation + +Since OpenPGP certificates act as ["append only" data structures](append-only), existing components or signatures cannot simply be "removed." Instead, they can be marked as invalid by issuing revocation signatures. These additional revocation signatures are added to the certificate. + +Each component, such as User ID and a subkey, can be revoked without affecting the rest of the certificate. + +The *primary User ID* is an exception: when it is revoked, the entire certificate is considered invalid. + +Revoking the primary key with a [*Key revocation signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-revocation-signature-ty) (type ID `0x20`) also marks the entire certificate, including all of its components, as invalid and unusable. + +### Semantics of Revocations + +In contrast to expiration, revocation is typically final and not withdrawn[^undo-revocations]. + +[^undo-revocations]: While some revocations can be reverted, undoing revocations is an uncommon workflow. Unlike expirations, which are commonly undone by extending the expiration time. + +A revocation indicates that the component should not be used. Revocation signatures over components use a [*Reason for Revocation*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#reason-for-revocation) subpacket to specify further details about the reason why the component or certification was revoked. The OpenPGP format specifies a set of distinct [values for *Reasons for Revocation*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#table-10), and additionally provides space for a human-readable free text field for comments about the revocation. + +Some libraries, such as Sequoia PGP, expose these distinct reasons for users, enabling nuanced machine-readable statements by the revoker. Other implementations focus mainly on the distinction between "hard" and "soft" revocations. + +Of the defined revocation types, *Key is superseded*, *Key is retired* and *User ID is no longer valid* are considered "soft" revocations. Any other reason (including a missing *reason for revocation* subpacket) means that the revocation is "hard." + +The distinction between hard and soft revocations plays a role when evaluating the validity of a component or signature at a specified reference time: Hard revocations have unbounded [temporal validity](temporal-validity), they are in effect even before their creation time and therefore invalidate the revoked component or signature at all points in time. + +By contrast, a soft revocation leaves the revoked component or signature valid before the creation time of the revocation signature. A soft revocation can technically be overridden, for example, with a newer binding signature (the new binding signature and its metadata then shadow the revocation and re-connect and re-validate the component). + +Hard revocations address the following problem: If a private key was compromised, then the attacker can issue signatures using that key. This means, the attacker could issue a signature dated before the revocation, impersonating the owner of the key. A recipient of that signature would mistakenly consider this signature valid if the issuing key has been soft revoked. This is a problem. +To counteract this problem, it is reasonable to clearly mark compromised keys as suspect at any point in time. That's what hard revocations do. + +On the other hand, if the subkey was merely retired using a soft revocation, and the certificate holder moved to a different subkey, then the signatures in the past, made by the retired key, are still valid. + +(append-only)= +## Certificates are effectively append-only data structures + +OpenPGP certificates act as *append-only data structures*, in practice. Packets that are associated with a certificate cannot be "recalled", once they were published. Third parties (such as other users, or keyservers) may keep and/or distribute copies of those packets. + +While it is not possible to *remove* elements, once they were publicly associated with an OpenPGP certificate, it is possible to invalidate them by adding new metadata to the certificate. This new metadata could set an *expiration time* on a component, or explicitly *revoke* that component. In both cases, no packets are removed from the certificate. + +Invalidation resembles removal of a component in a semantical sense. The component is not a valid element of the certificate anymore, at least starting from some point in time. Implementations that handle the certificate may omit the invalid component in their representation. + +We have to distinguish the "packet level" information about a certificate from an application-level view of that certificate. The two may differ. + +### Reasoning about append-only properties in a distributed system + +OpenPGP is a decentral and distributed system. Users can obtain and transmit certificate information about their own, as well as other users', certificates using a broad range of mechanisms. These mechanisms include keyservers, manual handling, [Web Key Directory](https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/) (WKD) and [Autocrypt](https://en.wikipedia.org/wiki/Autocrypt). + +Different users' OpenPGP software may obtain different views of a particular certificate, over time. Individual users' OpenPGP instances have to reconcile and store a combined version of the possibly disparate elements they obtain from different sources. + +In practice, this means that various OpenPGP users may have differing views of any given certificate. For various reasons, not all users will be in possession of a fully up-to date and complete version of a certificate. + +There are various potential problems associated with this fact: Users may not be aware that a component has been invalidated by the certificate holder. Revocations may not have been propagated to some third party. So for example, they may not be aware that the certificate holder has rotated their encryption subkey to a new one, and doesn't want to receive messages encrypted to the previous encryption subkey. + +One mechanism that addresses a part of this issue is *expiration*: By setting their certificates to expire after an appropriate interval, certificate holders can force their communication partners to refresh their certificate, e.g. from a keyserver[^mgorny]. + +[^mgorny]: See, for example, [here](https://blogs.gentoo.org/mgorny/2018/08/13/openpgp-key-expiration-is-not-a-security-measure/): "Expiration times really serve two purposes: naturally eliminating unused keys, and enforcing periodical checks on the primary key." + +Good practices, like setting appropriate expiration times, can mitigate the complexity of the inherently distributed nature of certificates. + +However, such mitigations by definition cannot address all possible cases of outdated certificate information in a decentralized, asynchronous system such as OpenPGP. So a defensive approach is generally appropriate when reasoning about the view of certificates that different actors have. + +When thinking about edge cases, it's useful to "assume the worst." For example: + +- Recipients may not obtain updates to a certificate in a timely manner (this could happen for various reasons, including, but not limited to, interference by malicious actors). +- Data associated with a certificate may compound, and a certificate can become too large for convenient handling, even in the course of normal operations (for example, a certificate may receive very many legitimate third-party certifications). If such a problem arises, then by definition, the certificate holder cannot address it: remember that the certificate holder cannot "recall" existing packets. + +### Differing "views" of a certificate exist + +Another way to think about this discussion is that different OpenPGP users may have a different view of any certificate. There is a notional "canonical" version of the certificate, but we cannot assume that every user has exactly this copy. Besides propagation of elements that the certificate holder has linked to a certificate, third-party certifications are by design a distributed mechanism. A third-party certification is issued by a third party, and may or may not be distributed widely by them, or by the certificate holder. Not distributing third-party certifications widely is a workflow that may be entirely appropriate for some use cases[^tpc-privacy]. + +[^tpc-privacy]: The two parties to a certification (the issuer and the target of the certification) may prefer not to publish their mutual association. Also see {ref}`social-graph-metadata-leak`. + +As a general tendency, it is desirable for OpenPGP users to have the most complete possible view of all certificates that they interact with. + +However, there are contexts in which it is preferable to only use a subset of the available elements of a certificate. We discuss this in the section {ref}`minimization`. + +(certificate-merging)= +## Merging + +As described above, OpenPGP certificates are effectively [append-only](append-only) data structures. As part of the practical realization of this fact, OpenPGP software needs to *merge* different copies of a certificate. + +For example, Bob's OpenPGP software may have a local copy of Alice's certificate, and obtain a different version of Alice's certificate from a keyserver. The goal of the implementation is to add new information about Alice's certificate, if any, to the local copy. Alice may have added a new identity, replaced a subkey with a new subkey, or revoked some components of her certificate. Or, Alice may have revoked her certificate, signaling that she doesn't want communication partners to use that certificate anymore. All of these updates could be crucial for Bob to be aware of. + +Merging two versions of a certificate involves making decisions about which packets should be kept. The versions of the certificate will typically contain some packets that are identical. No duplicates of the exact same packet should be stored in the merged version of the certificate. Additionally, if the newly obtained copy contains packets that are in fact entirely unrelated to the certificate, those should not be retained (a third party may have included unrelated packets, either by mistake, or with malicious intent). + +### Handling unauthenticated information + +For information that *is* related to the certificate, but not bound to it by a self-signature, there is no generally correct approach. The receiving implementation must revolve these cases, possibly in a context-specific manner. Such cases include: + +- Third-party certifications. These could be valuable information, where a third party attests that the association of an identity to a certificate is valid. On the other hand, they could also be a type of spam. +- Subpackets in the unhashed area of a signature packet. Again, these could contain information that is useful to the recipient. However, the data could also be either useless, or even misleading/harmful. + +(minimization)= +## Certificate minimization + +Certificate minimization is the practice of presenting a partial view of a certificate by filtering out some of its components. + +Filtering out some elements of a certificate can serve various purposes: + +- Omitting unnecessary components for specific use-cases. For example, email clients need encryption, signing and certification component keys, but not authentication subkeys, which are used, e.g., for SSH connections. +- Omitting third-party certifications if they are not required for a use-case. ["Certificate flooding,"](https://dkg.fifthhorseman.net/blog/openpgp-certificate-flooding.html) for example, can lead to consumer software rejecting a certificate entirely. Filtering out third-party User ID certifications on import can mitigate this. +- Sometimes, a certificate organically grows so big that the user software [has problems handling it](https://www.reddit.com/r/GnuPG/comments/bp23p4/my_key_is_too_large/). + +### Elements that can be omitted as part of a minimization process + +There are different types of elements that can be omitted during minimization: + +- Subkeys (along with signatures on those subkeys) +- Identity components (along with both their self-signatures and third-party signatures) +- Signatures, by themselves: + - Self-signatures that have been superseded by newer self-signatures for the same purpose + - Third-party certifications + +### Minimization in applications + +#### Hagrid, which runs keys.openpgp.org + +The [hagrid keyserver software](https://gitlab.com/keys.openpgp.org/hagrid) doesn't publish the identity components in certificates by default. This is a central aspect of the [privacy policy](https://keys.openpgp.org/about/privacy) of the service. Certificates can be uploaded to the service by third parties, which is useful. However, identifying information is only distributed by the service on an explicit opt-in basis. + +Separately, third-party certifications are currently filtered out by the service, to avoid flooding attacks. + +#### GnuPG + +GnuPG offers two explicit methods for certificate minimization, described [in the GnuPG manual](https://www.gnupg.org/documentation/manuals/gnupg-devel/OpenPGP-Key-Management.html) as: + +*clean* +: *Compact (by removing all signatures except the selfsig) any user ID that is no longer usable (e.g. revoked, or expired). Then, remove any signatures that are not usable by the trust calculations. Specifically, this removes any signature that does not validate, any signature that is superseded by a later signature, revoked signatures, and signatures issued by keys that are not present on the keyring.* + +*minimize* +: *Make the key as small as possible. This removes all signatures from each user ID except for the most recent self-signature.* + +`clean` removes third-party signatures by certificates that are not present in current keyring, as well as other stale data. `minimize` removes superseded signatures that are not needed at the point when the command is executed. + +Independently, GnuPG by default [strips some signatures on key import](https://dev.gnupg.org/T4607#127792)[^gpg-default-strip]. However, a number of Linux distributions change this default behavior, and continue to import signatures without minimization by default. e.g. [Debian](https://dev.gnupg.org/T4628#128513) and Arch Linux: stripping third-party certifications on import, by default, is problematic for users who want to leverage authentication based on the [Web of Trust mechanism](wot). + +[^gpg-default-strip]: GnuPG's changes in the default handling of third-party certifications on imports were prompted by the 2019 [keyserver flooding](keyserver-flooding) event. + +### Limitations that can result from stripping historical self-signatures + +Some implementations, such as Sequoia, prefer to rely on the full historical set of self-signatures to construct a view of the certificate over time. This way, signatures can be verified at different reference times. In this model, removing superseded self-signatures can cause problems with the validation of historical signature. + +An example for the tension between minimization and nuanced verification of the [temporal validity](temporal-validity) of signatures can be seen in the case of rpm-sequoia. See [this discussion](https://github.com/rpm-software-management/rpm-sequoia/issues/50#issuecomment-1689642607) for details: + +Initially, when checking the validity of a data signature for a software package, `rpm-sequoia` used the signature's creation time as the reference time. However, the availability of historical self-signatures in certificates is limited. So sometimes only a more recent self-signature for the primary key is available, and there is no evidence that the primary key was valid at the reference time. + +To deal with this reality, the rpm-sequoia implementation was adjusted to accept data signatures that predate the validity of the current primary key self-signature[^primary-self-sig]. + +[^primary-self-sig]: Which in OpenPGP version 4 is often a primary User ID binding signature. + +### Autocrypt + +The [Autocrypt](https://autocrypt.org/) project describes itself as: + +> [..] a set of guidelines for developers to achieve convenient end-to-end-encryption of e-mails. It specifies how e-mail programs negotiate encryption capabilities using regular e-mails. + +The Autocrypt Level 1 specification defines a specific [minimal format for OpenPGP certificates](https://autocrypt.org/level1.html#openpgp-based-key-data) that are distributed by the autocrypt mechanism. + +One goal of the Autocrypt mechanism is to distribute certificates widely. To this end, Autocrypt sends certificates in mail headers, where smaller size is greatly preferable. + +Basic encrypted email functionality requires only a small subset of the recipient's certificate, so small certificate size is feasible. + +### Minimization for email + +Note that minimization of certificates isn't generally "right" or "wrong." The benefit or harm depends on the context. + +For example, we might consider minimizing a certificate for distribution via WKD, with the use-case of email in mind. + +Many certificates can be significantly pruned if the only goal of distributing them is to enable encryption and signature verification. For such cases, many components can be dropped, including invalid subkeys and their binding signatures, authentication subkeys (which are irrelevant to email), shadowed self-signatures, and third-party certifications. With many real-world certificates, the space savings of such a minimization are significant[^space-example]. + +Such minimization might be appropriate and convenient to enable encrypted communication with a ProtonMail client, which automatically fetches OpenPGP certificates via WKD while composing a message. The ProtonMail use case requires only component keys, not third-party certifications, and it doesn't require historical component keys or self-signatures. + +However, in a different context, the same certificate might be fetched to verify the authenticity of a signature. In that case, third-party certifications may be crucial for the client. Stripping them could prevent the client from performing Web of Trust calculations and validating the authenticity of the certificate. + +[^space-example]: The following fragment processes an example certificate. It drops any subkey that is not valid at the time of export (because of revocation or expiration), authentication subkeys, and any third-party certifications: + + ```sh + gpg --export-options export-minimal,export-clean,no-export-attributes \ + --export-filter keep-uid=mbox=wiktor@metacode.biz \ + --export-filter 'drop-subkey=expired -t || revoked -t || usage =~ a' \ + --export wiktor@metacode.biz + ``` + + At the time of writing, the original certificate consists of 152322 bytes of data. The filtered variant consists of only 3771 bytes, which is 40x smaller. In some contexts, there are hard constraints on size, and minimization is unavoidable, e.g., when embedding certificate data in email headers. + +### Pitfalls of minimization + +Disadvantages/risks of minimizing certificates: + +- A minimized certificate does not present a full view of how it (and the validity of its components) evolved over time. +- As the OpenPGP subsystem on a user's computer learns about more certificates, third-party certifications that were previously unusable may become usable. Dropping third-party certifications by unknown issuers as a part of minimization prevents this mechanism. +- An OpenPGP implementation that minimizes a certificate might remove component keys that it cannot use itself (e.g. because it doesn't support the algorithm of that key), even if the *receiving* implementation supports them. +- Refreshing certificates from key servers may inflate the certificate again, since OpenPGP certificates tend to act as [append-only structures](append-only). +- Some libraries, such as [anonaddy-sequoia](https://gitlab.com/willbrowning/anonaddy-sequoia/-/blob/master/src/sequoia.rs?ref_type=heads#L125) strip unusable encryption subkeys, but retain at least one subkey, even if all subkeys are expired. Although this may leave only an expired encryption subkey in the certificate, this presents a better UX for the end-user who potentially is still in possession of the private key for decryption. + +## Guidelines + +1. Don't minimize certificates unless you have a good reason to. +2. When minimizing a certificate, minimize it in a way that suites your use-case. E.g., when minimizing a certificate for distribution alongside a signed software packet, make sure to include enough historical self-signatures as to not break the verification of the signed packet. +3. When presenting a minimized view of a certificate to a consumer, consider when that a new version of that view needs to be generated. Ideally, minimized certificates are freshly generated on demand (e.g., an Autocrypt header is constructed while an email is sent or composed). The receiver is expected to typically merge all data it sees locally. + +## Fingerprints and beyond: "Naming" certificates in user-facing contexts + +Certificates in OpenPGP have traditionally often been "named" using hexadecimal strings of varying length. + +For example, a business card might have shown the hexadecimal fingerprint of a person's OpenPGP certificate to facilitate secure communication. Over time, different formats and lengths for these identifiers have been used. + +This section outlines the various ways in which certificates can be named, and their properties. + +### Fingerprints and Key IDs in Version 4 + +With OpenPGP version 4 certificates, it was customary that user-facing software used 20 byte (160 bit) *fingerprints* as an identifier for the certificate. Or alternatively, the 8 byte (64 bit) *Key ID* variant of the fingerprint. Both were represented in hexadecimal format, sometimes with whitespace to group the identifier into blocks for easier readability. + +Workflows such as + +- accepting a certificate for a communication partner, or +- issuing a third-party certification for an identity, + +required users to manually compare the 40 character long hexadecimal representation of a fingerprint against a reference source for that fingerprint. + +### Fingerprints in Version 6 + +The OpenPGP version 6 standard uses 32 byte (256 bit) fingerprints, but explicitly defines no format for displaying those fingerprints in a human-readable form. The standard [recommends strongly against](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-fingerprint-usability) using version 6 fingerprints as identifiers in user-facing workflows. + +Instead, "mechanical fingerprint transfer and comparison" should be preferred, wherever possible. The reasoning is that humans tend to be bad at comparing high-entropy data[^schuermann] (in addition, many users are probably put off by being asked to compare long hexadecimal strings). + +[^schuermann]: See "An Empirical Study of Textual Key-Fingerprint Representations" + +### Use of Fingerprints and Key IDs in APIs + +However, both Fingerprints and Key IDs may (and usually *must*) be used, programmatically, by software that handles OpenPGP data, to address specific certificates. This is equally true for OpenPGP version 6. + +Note that regardless of the OpenPGP version, software that relies on 8-byte Key IDs should not assume that Key IDs are unique. It is trivial to generate collisions for 8-byte Key IDs, so applications must be able to handle Key ID collisions gracefully. + +The historical 4-byte "short Key IDs" format should not be used anywhere, anymore (finding collisions in a 32-bit keyspace has been [trivial for a long time](https://evil32.com/)). + +(certificate-lookup-by-email)= +### Looking up certificates by email + +Searching OpenPGP certificates by email is a use case that often arises. For example, when composing an email to a new contact, the sender may want to find the OpenPGP certificate for that contact. + +Different mechanisms allow certificate lookup by email, for example: + +- [Web Key Directory](https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/) (WKD) +- The [keys.openpgp.org](https://keys.openpgp.org/) "verifying keyserver" (also known as ["hagrid"](https://gitlab.com/keys.openpgp.org/hagrid), the name of the server software it runs) +- SKS-style OpenPGP keyservers (today, most of these run the [Hockeypuck](https://github.com/hockeypuck/hockeypuck) software) + +Their properties differ, for more see [](certificate-distribution). + +(certificate-freshness)= +## Certificate freshness: Triggering updates with an expiration time + +For a certificate holder, one problem is that their communication partners may not regularly poll for updates of their certificate. + +A certificate holder usually prefers that everyone else regularly obtains updates for their certificate. This way, a third party will, for example, not mistakenly keep using the certificate indefinitely, after it gets revoked. Setting an expiration time on the certificate, ahead of time, limits the worst case scenario: communication partners will at most use a revoked certificate until its expiration time, even if they never learn of the revocation. + +Once the expiration time is reached, third parties, or ideally their OpenPGP software will have to stop using the certificate, and may attempt to obtain an update for it. For example, from a keyserver, or via WKD. Ideally, certificate updates are obtained automatically, by the user's OpenPGP software, without any need for human intervention. + +After the update, the updated copy of the certificate will usually have a fresh expiration time. The same procedure will repeat once that new expiration time has been reached. + +(social-graph-metadata-leak)= +## Metadata leak of Social Graph + +Third-party certifications are signatures over identity components made by other users. + +These certifications form the back-bone of the OpenPGP trust-model called the Web of Trust. The name stems from the fact that the collection of certifications forms a unidirectional graph resembling a web. Each edge of the graph connects the signing certificate to the identity component associated with another certificate. + +OpenPGP software can inspect that graph. Based on the certification data in the graph and a set of trust anchors, it can infer whether a target certificate is legitimate. + +The trust anchor is usually the certificate holder's own key, but a user may designate additional certificates of entities they are connected to as trust anchors. + +Third-party certifications can be published as part of the target certificate to facilitate the process of certificate authentication. Unfortunately, a side effect of this approach is that it's feasible to reconstruct the entire social graph of all people issuing certifications. In addition, the signature creation time of certifications can be used to deduce whether the certificate owner attended a Key Signing Party (and if it was public, where it was held) and whom they interacted with. + +So, there is some tension between the goals of + +- a decentralized system where every participant can access certification information and perform analysis on it locally, +- privacy related goals (also see {ref}`certificate-lookup-by-email`, for a comparison of certificate distribution mechanisms, which also touches on this theme). + +(unbound-user-ids)= +## Adding unbound, local User IDs to a certificate + +Some OpenPGP software may add User IDs to a certificate, which are not bound to the primary key by the certificate's owner. This can be useful to store local identity information (e.g., Sequoia's public store attaches ["pet-names"][PET] to certificates, in this way). + +[PET]: https://sequoia-pgp.org/blog/2023/04/08/sequoia-sq/#an-address-book-style-trust-model + +Sequoia additionally certifies these "local, third party, User IDs" with a local trust anchor to facilitate local authentication decisions. +To prevent accidental publication of these local User IDs (e.g. to public keyservers), Sequoia marks these binding signatures as "local" artifacts using [Exportable Certification](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-exportable-certification) subpackets to mark them as non-exportable. + +(certificate-distribution)= +## Certificate distribution mechanisms + +Different mechanisms for discovering certificates, and updating certificate data exist in the OpenPGP space: + +- A *Web Key Directory* service is based on a well-known location on a webserver, serving certificates in a specific format. A WKD server is operated by the entity that controls the DNS domain of an email-based identity of a certificate. This means that WKD is inherently decentralized, and the reliability of OpenPGP certificates may vary depending on the organization that operates a particular WKD instance. +- The *keys.openpgp.org* service is a "verifying" keyserver: the keyserver software only publishes identity components (which include email addresses) after sending a verification email to that address, and receiving opt-in consent by the user of the email address. This service makes a different tradeoff: it is centralized, and relying on it to correctly perform the verification step requires trust in the operator. The tradeoff allows the service to only list identity information with the consent of the owner of that identity, and to prevent "enumeration" of the certificates and identities it stores (that is: third parties cannot obtain a list of email addresses in the service's database). By design, this service allows easy publication of revocations without requiring publication of any identity components. +- *SKS-style keyservers* act as a distributed synchronizing database, which accepts certificate information without verification. The SKS network handles third-party signatures, additional changes to their handling are pending[^hip1]. + +[^hip1]: + +One central difference between hockeypuck and hagrid (the software that runs the *keys.openpgp.org* service) is that hockeypuck distributes identity packets and third-party certifications that have indeterminate validity, while hagrid does not. + +(keyserver-flooding)= +## Third-party certification flooding + +Traditional OpenPGP keyservers are one mechanism for [collection and distribution](certificate-distribution) of certificate information. Their model revolves around receiving certificate information from sources that don't identify themselves to the keyserver network. Traditionally, these keyservers have accepted both components bound to certificates by self-signatures, and third party identity certifications. + +While a convenience for consumers, indiscriminately accepting and integrating third-party identity certifications comes with significant risks. + +Without any restrictions in place, malicious entities can flood a certificate with excessive certifications. Called "certificate flooding," this form of digital vandalism grossly expands the certificate size, making the certificate cumbersome and impractical for users. + +It also opens the door to potential denial-of-service attacks, rendering the certificate non-functional or significantly impeding its operation. + +The popular [SKS keyserver network experienced certificate flooding firsthand](https://dkg.fifthhorseman.net/blog/openpgp-certificate-flooding.html) in 2019, causing significant changes to its operation. + +```{note} +The *keys.openpgp.org* (KOO) service performs a similar function as the SKS-style keyservers. +However, there are major differences in its design and tradeoffs. + +The KOO keyserver was designed to: + +1. conform to [GDPR regulations](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation), and +2. be resistant to flooding-style vandalism. + +To achieve these goals, KOO does not serve identity components at all, unless an explicit opt-in has been performed, using a confirmation process vial email. Third-party certifications are also not served by default, but only under very specific circumstances, which preclude flooding. +``` + +### Hockeypuck-based keyservers + +Currently, third-party certification flooding can be worked around by users or administrators requesting the removal/re-adding of a certificate. [See here](https://github.com/hockeypuck/hockeypuck/wiki/HIP-1:-Regaining-control-over-public-key-identity-with-authenticated-key-management). + +Additional mechanisms [are upcoming](support-for-1pa3pc). + +## First-Party attested third-party certifications in OpenPGP (1pa3pc) + +[First-Party attested third-party certifications in OpenPGP](https://datatracker.ietf.org/doc/draft-dkg-openpgp-1pa3pc/) are a "mechanism to allow the owner of a certificate to explicitly approve of specific third-party certifications". 1pa3pc was designed to enable flooding-proof distribution of third-part certifications. + +This mechanism uses the *attested certifications* signature subpacket (type ID `37`), which currently only exists as a proposed feature in [draft-ietf-openpgp-rfc4880bis](https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#table-3)[^ac-draft]. + +[^ac-draft]: Introducing the *attested certifications* signature subpacket (type ID `37`) was unfortunately not in scope of the chartered topics for the current "crypto-refresh" work of the OpenPGP working group. However, hopefully the working group can handle this feature in future rechartering. + +(support-for-1pa3pc)= +### Support + +- The *keys.openpgp.org* (KOO) keyserver [supports *1pa3pc*](https://gitlab.com/keys.openpgp.org/hagrid/-/commit/39c0e12ac64588220d36bada6497d8396f5915b3). + +- The Hockeypuck keyserver software [plans to add support for *1pa3pc*](https://github.com/hockeypuck/hockeypuck/issues/136#issuecomment-1812466084) in version 2.2.0. + +- The Sequoia `sq` commandline tool [allows adding](https://man.archlinux.org/man/sq-key-attest-certifications.1) attested third-party certifications to a certificate. diff --git a/book/source/adv/decryption.md b/book/source/adv/decryption.md new file mode 100644 index 0000000..7811240 --- /dev/null +++ b/book/source/adv/decryption.md @@ -0,0 +1,29 @@ + + +# Advanced material: Decryption + +(decryption-seipd-quick-check)= +## Verify successful session key decryption + +SEIPDv1 packets might make use of a "quick check" mechanism to quickly verify that the correct session key was used without the need to decrypt the whole SEIPD packet. +This check consists of 16 random bytes, followed by a copy of the two last bytes, which are prefixed to the plaintext. +During decrypting, these 2 bytes can be compared to the 15th and 16th random byte to detect use of the wrong session key. + +Since the chance to accidentally end up with matching quick check bytes albeit the use of the wrong session key is 1:65536, some implementations validate further contents of the plaintext, such as the packet headers. + +The standard [warns against](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-risks-of-a-quick-check-orac) using the quick check mechanism, as it introduces the risk of a decryption oracle. Instead, the use of SEIPDv2 is recommended, as the AEAD mechanism automatically detects use of the wrong session key early on after the first chunk has been decrypted. + +(decryption-anonymous-recipient)= +## Anonymous recipients + +Having all recipients keys listed as part of the PKESK packets presents a metadata leakage. An observer can easily enumerate recipients of a message by comparing the PKESKs with certificates of potential recipients. + +To prevent this issue, the sender can decide to add individual recipients as anonymous recipients using a wildcard key-ID / fingerprint. +This is done by creating a normal PKESK packet for the recipient, but setting the recipient key field to `0` (as well as omitting the version number of the key for v6 PKESKs). + +A recipient of such a message that does not find a PKESK addressed specifically to any of their keys, can then try to decrypt any anonymous PKESK packets using any of their encryption subkeys. + +To reduce the number of keys to try, the recipient can skip all secret keys which do not share the public-key algorithm stated in the PKESK packet. diff --git a/book/source/adv/encryption.md b/book/source/adv/encryption.md new file mode 100644 index 0000000..b2b5631 --- /dev/null +++ b/book/source/adv/encryption.md @@ -0,0 +1,32 @@ + + +# Advanced material: Encryption + +## Encrypt to multiple/single subkey per certificate? + +A recipient's certificate can contain more than one usable encryption subkey. +This raises the question, should the message be encrypted for all of them? + +There is the argument that a powerful attacker might have managed to add an attacker-controlled encryption subkey to the victim's certificate. +In this case, only encrypting to the "newest" encryption key would help uncover such an attack. However, a powerful attacker could just MitM any sent messages and just add a PKESK for the victim-controlled encryption keys to hide the fact that the sender used a different key. + +On the other hand, a user might have multiple encryption subkeys on purpose. +Picture, for example, a scenario where the same certificate is used on multiple devices, but each device has dedicated encryption subkeys to allow for smoother revocation in case of a lost device. +In this scenario, it is important that the sender encrypts the message to all available encryption subkeys. + +## "Negotiating" algorithms based on recipients preference subpackets + +### Prevent "downgrade" -> Policy + +Each implementation should define a "minimum" level of security when it comes to algorithms and key lengths. +If the lowest common denominator of symmetric encryption algorithms preferred by a set of recipients provides too little security, the implementation should either use a configured fallback algorithm instead, or fail to produce a message at all. + +## AEAD modes in v2 SEIPD: GCM + +```{note} + +This section is still about to be written. +``` diff --git a/book/source/adv/private_keys.md b/book/source/adv/private_keys.md new file mode 100644 index 0000000..319a914 --- /dev/null +++ b/book/source/adv/private_keys.md @@ -0,0 +1,82 @@ + + +# Advanced material: Private keys + +(key-store-design)= +## Private keystores + +This section examines the diverse architectures and operational mechanics of private keystores in OpenPGP. It focuses on the various design choices, their functional implications, and how they contribute to the secure management of private key material. + +### Design variations + +The design of private key subsystems within the OpenPGP framework varies, offering different approaches to cryptographic operations: + +1. **Separate backend operations**: Some designs execute the primitive cryptographic operations in a separate backend, using only the cryptographic key material. This approach is particularly compatible with general purpose hardware cryptographic devices, such as [trusted platform modules (TPMs)](https://en.wikipedia.org/wiki/Trusted_Platform_Module). +2. **Component key-based systems**: An OpenPGP private key subsystem may be built around component keys, specifically the content of [Secret-Key packets](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats). These packets contain metadata that is required for some operations. ECDH operations, in particular, require metadata as KDF parameters. +3. **Full transferable secret keys**: Some designs maintain copies of full TSKs in the private key subsystem, leveraging these for private key operations. + +While private keystore operations require component keys, they do not require access to the entire OpenPGP certificate. + +```{note} +The third design option, involving the storage of full TSKs in the private key subsystem, can cause "split brain" problems. + +For example, a private keystore might contain a TSK with outdated certificate metadata, marking the certificate as expired, while the updated version in the local public keystore could indicate an extended expiration time. + +This problem was notably present in GnuPG 1.x, which held separate TSK copies in its private store component. Similarly, the current design of Thunderbird's OpenPGP subsystem can lead to users experiencing such issues. +``` + +### Two-tier architecture + +At its core, an OpenPGP private key subsystem performs operations requiring only the private cryptographic key material, akin to the "separate backend operations" model described above. + +However, the subsystem also supports operations that require additional access to the metadata of the component key. These operations, supplementary to the core keystore operations, do not involve the private key material. + +When implementing a keystore based on hardware cryptographic devices like [OpenPGP card](openpgp-card), its design will consist of two layers: + +- **core layer**: directly handles private key material, and +- **supplementary layer**: performs additional cryptographic operations that don't directly use the private key material, such as [AES key wrap](https://www.rfc-editor.org/rfc/rfc3394.html) for ECDH. + +```{note} + The decryption process using ECC algorithms, especially ECDH, has multiple steps. The initial step, potentially performed by devices such as OpenPGP cards, directly uses private key material to produce a "shared secret." Following this, operations like ["AES key unwrap"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-ec-dh-algorithm-ecdh) are conducted in software outside the hardware device. + + Further details on this process can be found in the "Advanced Encryption Standard (AES) Key Wrap Algorithm" [RFC 3394](https://www.rfc-editor.org/rfc/rfc3394.html). +``` + +### Addressing individual keys + +A critical aspect of private keystore design involves determining how users address individual keys. + +One common method is using the fingerprint of each component key. The availability of these fingerprints, however, depends on the underlying technology of the keystore. For instance, in software-based private keystores or OpenPGP cards, fingerprints of component keys are usually readily available. Keystores relying on generic cryptographic hardware, like TPMs, need to implement their own mechanisms for tracking and managing the fingerprints of each key. + +### Additional keystore duties + +In addition to key management, a keystore often involves various supplementary functions: + +- **Tracking devices**: Keystores may track which devices contain particular component keys. + +- **Handling secrets**: This involves the management of sensitive information such as passphrases for software keys or PINs for OpenPGP cards. + +- **User interaction alerts**: Keystores might also need to prompt users for necessary interactions during certain operations. For example, OpenPGP cards may require user touch confirmation to authorize each cryptographic action. + +## Understanding key overwriting (KO) attacks + +### What they are + +OpenPGP is subject to specific vulnerabilities known as key overwriting (KO) attacks. These attacks exploit weaknesses in how encrypted private keys or their metadata are handled, potentially leading to the leakage of secret data when the key is used. The core issue lies in OpenPGP's handling of Secret-Key packets, where corruption of the non-encrypted fields can cause the unaltered private key material to be used with altered parameters. This mismatch can result in private key leakage. + +Importantly, KO attacks are particularly relevant when an attacker is responsible for storing a user's encrypted private key. By altering the algorithm field in the Secret-Key packet, the attacker may cause the user to perform a cryptographic operation with a different algorithm. E.g., performing a DSA operation with ECC private key material. By observing the output of that attacker-corrupted operation, the attacker can recover the user's unencrypted private key material, even though the attacker had no direct access to it. + +### Mitigation + +Understanding KO attacks is crucial due to their potential to compromise the integrity and confidentiality of encrypted communications, and the risk of complete private key material compromise. KO attacks highlight the necessity for robust key validation procedures and the dangers of storing keys in insecure environments. OpenPGP application developers should consider if this attack class is a concern in their applications. + +Private keys that are protected with [S2K usage mode 253 (AEAD)](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption), are not vulnerable to KO attacks. This mode ensures the integrity of the private key by using its unencrypted fields (including the algorithm field) as the *authentication tag* for integrity verification in the decryption process. When an attacker alters the unencrypted part of the packet, then decryption of the private key material will fail, and the user is prevented from e.g. accidentally using the key material with an altered attacker-controlled algorithm. + +Note that while S2K usage mode 253 (AEAD) has been introduced in the OpenPGP version 6 specification, it can also be applied to OpenPGP version 4 key material (also see {ref}`migration-s2k`). + +#### Resources + +For comprehensive information on KO attacks, including background, attack vectors, countermeasures, and technical analyses, visit [KOpenPGP.com](https://www.kopenpgp.com/). It is based on the paper "Victory by KO: Attacking OpenPGP Using Key Overwriting" written by Lara Bruseghini, Daniel Huigens, and Kenneth G. Paterson for the Proceedings of ACM Conference on Computer and Communications Security, Los Angeles, November 2022. diff --git a/book/source/adv/signatures.md b/book/source/adv/signatures.md new file mode 100644 index 0000000..daf2769 --- /dev/null +++ b/book/source/adv/signatures.md @@ -0,0 +1,55 @@ + + +# Advanced material: Signatures + +(notation-signature-subpackets)= +## Notation signature subpackets + +[Notation signature subpackets](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#notation-data) can be used to effectively extend the otherwise limited set of {term}`signature subpacket types` in OpenPGP with user-defined {term}`notations`. {term}`Issuers` can use these {term}`notations` to add name-value pairs to an {term}`OpenPGP signature`. + +{term}`Notation` names - strings encoded in UTF-8 - may reside in the "user namespace." This namespace is characterized by a {term}`notation tag`, followed by a DNS domain name, both in UTF-8 format. + +{term}`Notations`, as described earlier, allow for user-defined extensions to the {term}`OpenPGP signature subpacket types`. A practical and popular application of this functionality is seen in Keyoxide, a decentralized {term}`identity verification` service. Keyoxide uses {term}`notations` in the `ariadne.id` namespace. For the details of this {term}`implementation`, refer to the [Keyoxide documentation](https://docs.keyoxide.org/wiki/ariadne-identity/). + +## Choosing the hash algorithm for a signature + +A central element of signature packets is the hash digest of the input data. Most OpenPGP software supports a set of different hash mechanisms, of which one is chosen for each signature packet (this is one aspect of OpenPGP's *cryptographic agility*), and used to calculate the hash digest. + +Different hash mechanisms offer different trade-offs: + +- *Hash digest size*: Larger hash size tends to correspond with greater strength against cryptanalysis, and hash digests are relatively small: at the time of this writing, typical sizes are 32 to 64 bytes. However, for some use cases - especially where small messages are sent over a bandwidth-limited transport - larger hash sizes may unacceptably increase message size. +- *Computational cost*: Different hash algorithms may have different computational costs. Some OpenPGP users may prefer to limit this cost, for example on constrained computing environments. + +The following sections discuss how the hash algorithm is chosen, based on preferences that are associated with the involved OpenPGP certificates. + +### Typically: Local determination + +Often, signature creation isn't targeted at a specific receiver. Many signatures are issued for an indeterminate set of "anyone who receives the signature." + +For example, self-signatures that form a certificate are aimed at everyone who interacts with that certificate. Similarly, when creating a data signature for a software package, this signature is aimed at "anyone who will check the signature," often over a long period of time, easily spanning years. + +In such cases, the issuer of that signature chooses the hash algorithm locally, without following preferences of a third party. + +### With a specific recipient: "Negotiation" based on recipient's preferences + +In contrast, when a message is created for a specific recipient, the sender can - and should - choose the hash algorithm for the signature packet [based on the recipient's hash algorithm preference](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-hash-algorithm-preferences). + +The recipient's hash algorithm preference is defined in metadata of their certificate, see {ref}`preferences-features` for more details. + +In this workflow, the signed hash digest is created with a hash algorithm that follows the recipient's preferences, and its intersection with the sender's capabilities and preferences. + +## Signature versions + +As described in the [RFC](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-packet-type-id-2), the version of a generated signature packet must conform to the version of the key that issues the signature. + +That is: + +- OpenPGP version 6 keys must generate version 6 signature packets +- OpenPGP version 4 keys must generate version 4 signature packets + +Note that some historical version 3 signature packets may still be relevant for applications that handle old OpenPGP data[^sig-v3]. These version 3 signature packets will have been generated by version 4 keys. + +[sig-v3]Version 4 signature packets were introduced in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440#section-5.2) in 1998, which specifies that applications SHOULD generate v4 signature, however generation of v3 signature packets has remained allowed through [RFC 4880](https://www.rfc-editor.org/rfc/rfc4880.html#section-5.2). diff --git a/book/source/adv/signing_components.md b/book/source/adv/signing_components.md new file mode 100644 index 0000000..b170691 --- /dev/null +++ b/book/source/adv/signing_components.md @@ -0,0 +1,145 @@ + + +# Advanced material: Signatures on components + +## Certification recipes + +Different {term}`signatures` in OpenPGP serve various specific purposes. This section provides practical guidance on creating these {term}`signatures`, illustrating each with concrete examples. + +(recipe-algorithm-preferences)= +### Change algorithm preferences + +To modify the preferred {term}`symmetric`, compression, {term}`hash`, or {term}`AEAD algorithms` for a {term}`key`, the {term}`key owner` needs to issue a {term}`direct key signature` ({term}`type ID` `0x1F`) on the {term}`primary key`. + +This {term}`signature` should have the following structure: + +| {term}`Subpacket` | Area | {term}`Critical` | Mandatory | Notes | +|---------------------------------------------------------------------------------------------|-----------------------------|------------------------------------------|----------------------|----------------------------------------------------------------------------------------| +| {term}`Signature Creation Time` | {term}`Hashed` | True | True | Current time | +| {term}`Issuer Fingerprint` | {term}`Hashed` | True or False | Strongly Recommended | The {term}`primary key` is the {term}`issuer` | +| {term}`Key Flags` | {term}`Hashed` | True | False | Retain {term}`key flags` from the previous {term}`self-signature` | +| {term}`Features` | {term}`Hashed` | True | False | Retain {term}`features` from the previous {term}`self-signature` | +| {term}`Key Expiration Time` | {term}`Hashed` | True | False | Retain {term}`expiration time` from the previous {term}`self-signature`, if applicable | +| {term}`Hash Algorithm Preferences` | {term}`Hashed` | False | False | New {term}`preferences` | +| {term}`Compression Algorithm Preferences` | {term}`Hashed` | False | False | New {term}`preferences` | +| {term}`Symmetric Algorithm Preferences` | {term}`Hashed` | False | False | New {term}`preferences` | +| {term}`AEAD Algorithm Preferences` | {term}`Hashed` | False | False | New {term}`preferences` | + +### Change expiration time + +To adjust the {term}`expiration time` of an {term}`OpenPGP certificate`, a new *{term}`DirectKey`* {term}`signature` ({term}`type ID` `0x1F`) with a modified {term}`Key Expiration Time subpacket` must be issued. The structure of this {term}`signature` is identical to the one outlined in the previous section on changing {term}`algorithm preferences`. + +Additionally, the {term}`expiration time` can be altered for individual {term}`User IDs` (detailed below) or separate {term}`subkeys` (see {numref}`bind-subkey`). + +### Add User ID + +To {term}`bind` a {term}`User ID` to an {term}`OpenPGP certificate` a {term}`certification signature` ({term}`type ID` `0x10`-`0x13`) is used which should have the following structure: + +| {term}`Subpacket` | Area | {term}`Critical` | Mandatory | Notes | +|------------------------------------------------------------------------|-----------------------------|------------------------------------------|----------------------|-------------------------------------------------------------------------------------| +| {term}`Signature Creation Time` | {term}`Hashed` | True | True | Current time | +| {term}`Issuer Fingerprint` | {term}`Hashed` | True or False | Strongly Recommended | The {term}`primary key` is the {term}`issuer` | +| {term}`Primary User ID` | {term}`Hashed` | True | False | Optional | +| {term}`Signature Expiration Time` | {term}`Hashed` | True | False | Optional | + +In addition to these {term}`subpackets`, {term}`self-certifications` for {term}`User IDs` can include others – such as {term}`key flags`, {term}`features`, and {term}`algorithm preferences` – as shown in the previous table. This enables the specification of unique capabilities and {term}`preferences` for each {term}`identity` associated with the {term}`certificate`. + +### Remove or revoke a User ID + +Since {term}`OpenPGP certificates` are often distributed by the means of {term}`key servers`, new {term}`signatures` on a {term}`certificate` are often "[merged](certificate-merging)" into existing copies of the {term}`certificate` locally by the recipient. + +This integration process means it is practically impossible to directly remove {term}`signatures` or {term}`User IDs` from a {term}`certificate`, as there is no way to communicate the intention of {term}`packet` deletion to the recipient. + +To effectively mark a {term}`User ID` as invalid, the user can publish a copy of their {term}`certificate` with a {term}`Certification Revocation signature` ({term}`type ID` `0x30`) attached to the invalidated {term}`User ID`. This {term}`signature` signals that the specified {term}`User ID` is no longer valid or associated with the {term}`certificate holder`. + +The structure of a {term}`Certification Revocation signature` is as follows: + +| {term}`Subpacket` | Area | {term}`Critical` | Mandatory | Notes | +|--------------------------------------------------------------------|-----------------------------|------------------------------------------|----------------------|-------------------------------------------------------------------------------------| +| {term}`Signature Creation Time` | {term}`Hashed` | True | True | Current time | +| {term}`Issuer Fingerprint` | {term}`Hashed` | True or False | Strongly Recommended | The {term}`primary key` is the {term}`issuer` | +| {term}`Reason for Revocation` | {term}`Hashed` | True | False | Determines {term}`soft` or {term}`hard revocation` | + +For {term}`User ID` {term}`revocations`, the *{term}`Reason for Revocation`* {term}`subpacket` is crucial. A value of `0` means no specific reason, leading to a {term}`hard revocation`, while `32` indicates the {term}`User ID` is no longer valid, resulting in a {term}`soft revocation`. Omitting the {term}`reason subpacket` is also equivalent to a {term}`hard revocation`. + +It is generally advisable to use reason code `32` for revoking {term}`User IDs`. + +(recipe-binding-subkeys)= +### Add a subkey + +As part of {term}`life-cycle management`, users may need to add a new {term}`subkey` to their {term}`OpenPGP certificate`, often for reasons such as upgrading to a {term}`subkey` with more advanced cryptographic algorithms. The process involves creating a specific {term}`signature` structure: + +| {term}`Subpacket` | Area | {term}`Critical` | Mandatory | Notes | +|---------------------------------------------------------------------------------------------|-----------------------------|------------------------------------------|-------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| {term}`Signature Creation Time` | {term}`Hashed` | True | True | Current time | +| {term}`Issuer Fingerprint` | {term}`Hashed` | True or False | Strongly Recommended | The {term}`primary key` is the {term}`issuer` | +| {term}`Key Flags` | {term}`Hashed` | True | Strongly Recommended | Determine the usage of the {term}`key` | +| {term}`Key Expiration Time` | {term}`Hashed` | True | False | Specifies the {term}`expiration time` of the {term}`subkey` | +| {term}`Embedded Signature` | {term}`Hashed` | True | If {term}`Key Flags` contains **{term}`S`** | {term}`Signing subkeys` require embedded *{term}`Primary Key Binding`* {term}`signature` | +| {term}`Hash Algorithm Preferences` | {term}`Hashed` | False | False | Per {term}`key` {term}`preferences` | +| {term}`Compression Algorithm Preferences` | {term}`Hashed` | False | False | Per {term}`key` {term}`preferences` | +| {term}`Symmetric Algorithm Preferences` | {term}`Hashed` | False | False | Per {term}`key` {term}`preferences` | +| {term}`AEAD Algorithm Preferences` | {term}`Hashed` | False | False | Per {term}`key` {term}`preferences` | + +In addition to these {term}`subpackets`, users can specify {term}`algorithm preferences` for each {term}`subkey`, distinct from those set in the {term}`certificate`'s *{term}`Direct Key`* {term}`signature`. + +### Revoke a subkey + +{term}`Subkeys`, like {term}`User IDs`, can be individually revoked in OpenPGP. +This is done by issuing a {term}`Subkey Revocation signature` ({term}`type ID` `0x28`) using the {term}`primary key`. + +The structure of such a {term}`signature` is straightforward: + +| {term}`Subpacket` | Area | {term}`Critical` | Mandatory | Notes | +|--------------------------------------------------------------------|-----------------------------|------------------------------------------|----------------------|-------------------------------------------------------------------------------------| +| {term}`Signature Creation Time` | {term}`Hashed` | True | True | Current time | +| {term}`Issuer Fingerprint` | {term}`Hashed` | True or False | Strongly Recommended | The {term}`primary key` is the {term}`issuer` | +| {term}`Reason for Revocation` | {term}`Hashed` | True | False | Determines {term}`soft` or {term}`hard revocation` | + + +In {term}`Subkey Revocation signatures`, the [reason for revocation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-reason-for-revocation) {term}`subpacket` can only have values in the range of `0-3`. The values `1` ({term}`key` superseded) and `3` ({term}`key` retired and no longer used) indicate {term}`soft revocations`, whereas values `0` (no reason) and `2` ({term}`key` compromised) indicate {term}`hard revocations`. + +Note that a value of `32` is not applicable in these {term}`signatures`. + +### Revoke a certificate + +Users may find themselves needing to revoke their entire {term}`OpenPGP certificate`, rendering it unusable. This could be for various reasons, such as migrating to a new {term}`certificate` or in response to a compromise of the {term}`certificate`'s {term}`secret key material`. + +While a {term}`soft-revoked` {term}`certificate` can be re-validated at a later time with a new {term}`certification`, a {term}`hard revocation` is permanent. + +The recommended way to {term}`revoke` a {term}`certificate` is by issuing a {term}`Key Revocation signature` ({term}`type ID` `0x20`). Its structure is similar to that of a {term}`Certification Revocation signature`. + +| {term}`Subpacket` | Area | {term}`Critical` | Mandatory | Notes | +|--------------------------------------------------------------------|-----------------------------|------------------------------------------|----------------------|-------------------------------------------------------------------------------------| +| {term}`Signature Creation Time` | {term}`Hashed` | True | True | Current time | +| {term}`Issuer Fingerprint` | {term}`Hashed` | True or False | Strongly Recommended | The {term}`primary key` is the {term}`issuer` | +| {term}`Reason for Revocation` | {term}`Hashed` | True | False | Determines {term}`soft` or {term}`hard revocation` | + +For {term}`Key Revocation signatures`, the guidelines regarding the [*Reason for Revocation* subpacket](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-reason-for-revocation) are the same as those for {term}`Subkey Revocation signatures`. + +### Common subpackets in OpenPGP signatures + +In OpenPGP, certain {term}`subpackets` are universally expected across all types of {term}`signatures`, serving fundamental roles in the {term}`signature`'s structure, {term}`verification` and {term}`validation`: + +* **{term}`Signature Creation Time`**: This is a mandatory {term}`subpacket` in every {term}`OpenPGP signature`. It contains the timestamp of when the {term}`signature` was created. For security and integrity, this {term}`subpacket` must be located in the {term}`hashed area` of the {term}`signature` and is recommended to be marked as {term}`critical`. + +* **{term}`Issuer Fingerprint`**: Essential for {term}`signature` {term}`validation`, this {term}`subpacket` identifies the {term}`key` (or {term}`subkey`) that was used to create the {term}`signature`. OpenPGP v6 {term}`signatures` should include the {term}`Issuer Fingerprint subpacket`, containing the 32-byte {term}`fingerprint` of the {term}`key`. + +```{note} +The {term}`key` used as the {term}`issuer` in the {term}`signature` might be a {term}`subkey` of the {term}`certificate`. +``` + +These {term}`subpackets` can be placed in either the {term}`hashed` or {term}`unhashed area` due to its self-{term}`authenticating` nature. However, we recommend including them in the {term}`signature`'s {term}`hashed area`. + +## Managing subpacket conflicts and duplication + +In {term}`OpenPGP signatures`, both the {term}`hashed` and {term}`unhashed areas` are composed of lists of {term}`subpackets`. Inherently, this structure permits the duplication of the same {term}`subpacket`, which could lead to conflicts. To manage these potential conflicts, the following strategies are used: + +- **Precedence of {term}`hashed area`**: {term}`Subpackets` within the {term}`hashed area` of a {term}`signature` take precedence over those in the {term}`unhashed area`. This hierarchy helps resolve conflicts when the same {term}`subpacket` appears in both areas. + +- **Handling conflicts within the same area**: Conflicts can still arise within the same area, such as when two {term}`subpackets` have different {term}`expiration times`. In such cases, the [OpenPGP specification](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-notes-on-subpackets) advises that {term}`implementations` should favor the last occurrence of a conflicting {term}`subpacket` in the {term}`hashed area`. + +In certain scenarios, having duplicate {term}`subpackets` with conflicting content is logical and even necessary. For example, consider a {term}`signature` created by a version 4 {term}`issuer` {term}`key`, which was upgraded from an older OpenPGP version (like v3). Since the {term}`key ID` calculation scheme changed from v3 to v4, the identifiers for the same {term}`key` would differ between these versions. Therefore, a v4 signature might contain two {term}`issuer key ID subpackets`, each with different, yet correct values for v3 and v4 {term}`keys`, respectively. This allows for backward compatibility and ensures the {term}`signature` can be {term}`validated` under both {term}`key ID` calculation schemes. diff --git a/book/source/adv/signing_data.md b/book/source/adv/signing_data.md new file mode 100644 index 0000000..f031233 --- /dev/null +++ b/book/source/adv/signing_data.md @@ -0,0 +1,52 @@ + + +# Advanced material: Signatures over data + +## Nesting of one-pass signatures + +Signing a message using the one-pass mechanism involves prepending a *One-Pass-Signature* (OPS) packet to the message and appending the corresponding signature, sandwiching the signed content. + +An OpenPGP message can contain multiple signatures added that way. + +```{note} +One-Pass-Signatures are nested, meaning the outermost One-Pass-Signature packet corresponds to the outermost signature packet. +``` + +When a message is signed, the signature is always calculated over the contents of the literal data packet, not the literal data packet itself. +This means, that if a message, which is compressed using a compressed data packet is wrapped using a one-pass-signature, the signature is still being calculated over the plaintext inside the literal data packet. + +There is one exception though. +```{note} +Of course there is. +``` + +The OPS packet has a "nested" flag[^nested-flag], which can either be `1` or `0`. +If this flag is set to `0`, it indicates that further OPSs will follow this packet, which are calculated over the same plaintext data as this OPS is. A value of `1` indicates, that either no further OPS packets will follow (this OPS is the last), or that this OPS is calculated over the the usual plaintext data, but wrapped inside any OPS+Signature combinations that follow this OPS. + +[^nested-flag]: See [description of the nested flag](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-5.4-3.8.1). + +This mechanism enables attested signatures, where the signer signs an already one-pass-signed message including the already contained signature. + +As a practical example, consider the following notation: +* `LIT("Hello World")` represents a literal data packet with the content `Hello World`. +* `COMP(XYZ)` represents a compressed data packet over some other packet `XYZ`. +* `OPS₁` represents a one-pass-signature packet with the nested flag set to `1`. Analogous, `OPS₀` has the nested flag set to `0`. +* `SIG` represents a signature packet. + +A normal, one-pass-signed message looks like this: +`OPS₁ LIT("Hello World") SIG` + +Here, the signature is calculated over the plaintext `Hello World`, as is it in a message that has the following form: `OPS₁ COMP(LIT("Hello World")) SIG`. + +A message, where multiple one-pass-signatures are calculated over the same plaintext looks the following: +`OPS₀ OPS₀ OPS₁ LIT("Hello World") SIG SIG SIG` + +All three signatures are calculated over the same plaintext `Hello World`. + +Now, a message, where the signer attests an already signed message has the following format: +`OPS₁ OPS₁ LIT("Hello World") SIG SIG` + +While the inner signature is calculated over the usual plaintext `Hello World`, the outer signature is instead calculated over `OPS₁ Hello World SIG`. diff --git a/book/source/adv/verification.md b/book/source/adv/verification.md new file mode 100644 index 0000000..dc21217 --- /dev/null +++ b/book/source/adv/verification.md @@ -0,0 +1,116 @@ + + +# Advanced material: Signature verification + +## Attribute shadowing + +When determining the preferences of a key, several signatures may have to be inspected. + +For example, when using a signing subkey to generate a data signature, an implementation might want to check for hash algorithm preferences on the subkey binding signature. +However, the RFC [states](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-5.2.3.10-2) that signature subpackets in a direct key signature (which may also contain preferences) on the OpenPGP certificate's primary key apply to the entire OpenPGP key, and therefore also to the signing subkey. + +In this case, the implementation uses the preferences from the subkey binding signature, but if no such subpacket is found on the latest binding signature, it falls back to the preferences from the direct key signature. +This is called attribute shadowing, since direct key signature subpackets apply to all subkeys, but are shadowed by binding signature subpackets. + +```{figure} ../img/drawio/attribute-shadowing.png +:name: fig-signature-verification-attribute-shadowing +:alt: Depicts a certificate with to dedicated signing subkeys and a subkey binding signature each. The primary key carries a direct-key signature, which specifies SHA-512 and SHA-256 as hash algorithm preferences. The binding signature of the first signing subkey does not specify preferences, while the binding signature of the second subkey defines SHA-384. Signatures made using the first subkey source the hash algorithm preferences from the direct-key signature, due to the absence of a preference subpacket on the binding signature, while for signature made using the second subkey the direct-key signature's preferences are shadowed by the subkey signatures preferences subpacket. + +Inheritance and Shadowing of Attributes +``` + +```{admonition} Note +:class: note + +Attribute shadowing is relatively straightforward to reason about when used for algorithm preferences. For other subpacket types, shadowing may be confusing, and/or the semantics underspecified (e.g. for key expiration time subpackets). +``` + +## Signature shadowing + +When inspecting signatures on a component of an OpenPGP certificate, of the signatures that are in effect for each function, only the newest is considered. + +In other words: +- If there are three binding signatures `A, B, C` for a subkey, +- where: + - `A` was created at `t0`, + - `B` at `t1`, and + - `C` at `t3`, with + - `t0 < t1 < t2 < t3`. +- Then at `t2`, an implementation only needs to consider signature `B`, + - because `C` is not yet in effect, and + - `A` is shadowed, because it is older than `B`. + +```{figure} ../img/drawio/cert-validity-subkey.png +:name: fig-signature-verification-subkey-validity +:alt: Depicts a gantt-style diagram visualizing how the validity of a certificates components changes over time, depending on component signatures. + +An example for how certificate validity can change with time. +``` + +```{note} + +Signature shadowing should not be confused with attribute shadowing. +``` + +As attribute and signature shadowing can occur in combination, it is not always obvious which properties a key has at a given time. + +```{figure} ../img/drawio/dk-attributes-and-shadowing.png +:name: fig-signature-verification-signature-shadowing +:alt: Depicts a certificate with a subkey, whose capabilities change over time, due to signature shadowing another. + +Signatures shadow one another, based on reference time. +``` + +## Which signatures take precedence? + +Multiple signatures can be attached to an OpenPGP certificate or component. These signatures can contain conflicting information. + +When verifying a signature that is not self-qualifying, an implementation needs to inspect self-qualifying signatures in the issuer's certificate for qualification. The certificate may contain multiple signatures for one component. + +For example, there could be multiple subkey binding signatures for one subkey. This could be the case because the expiration time in the original binding signature has expired, and the certificate holder has issued a new binding signature with an extended expiration time. + +In general, for each category of signatures (categories such as binding signatures for one particular subkey), the signature with the latest creation time takes precedence, and only that signature is considered. + +Alternatively, there can be competing qualifying signatures of different types, e.g., a direct key signature and a self-certification signature on a primary User ID. Both of these contain metadata associated with the entire certificate. By default, the direct key signature is preferred[^conflicting-prefs] in OpenPGP version 6. + +[^conflicting-prefs]: However, the semantics of these cases are not currently fully specified, see [this discussion](https://gitlab.com/openpgp-wg/rfc4880bis/-/issues/103). + +Depending on how a certificate is "located," different metadata from possible candidate signatures "shadow" one another. The RFC [states](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-notes-on-self-signatures) that when a certificate is "located" by the OpenPGP software "via an identity", then the metadata associated with that identity takes precedence over more global metadata, such as that associated with the certificate's primary key, with a direct key signature. + +For example, the latest direct key signature could list "SHA512, SHA384" as hash algorithm preferences, while the latest self-certification of the User ID "Bob" could list only "SHA256." +For yet another User ID "Bobby," the self-signature could list no hash algorithm preferences at all. +If the user wants to compose a signed message using the associated OpenPGP key they need to figure out which preferences to use. + +The specification recommends that implementations decide which signature takes precedence by the way the certificate is "addressed." + +```{figure} ../img/drawio/narrow-interpretation.png + +Preferences are sourced from signatures on different components, depending on how the key is addressed. +``` + +If the user wants to write an email as "Bob," it should consider the signature on "Bob," so SHA256 should be used as hash algorithm. +If instead the user wants to write as "Bobby," the implementation should inspect the self-certification on "Bobby" instead. +However, since this signature does not carry any hash algorithm preferences subpacket, the implementation must fall back to the direct key signature instead. +The same is true if the certificate is used without any User ID as sender. + +To complicate things further: +Algorithm preferences can also be stated on subkey binding signatures, so if the certificate has a dedicated signing subkey, there is yet another signature which could take precedence. +Preferences from the subkey binding signature take precedence over the direct key signature, but not over self-certifications on the User ID. + +There can be more than one signature on a component. As an example, there are 3 direct key signatures (e.g., because the key's expiry has been extended two times). +In general, for each component, only the newest self-signature is "in effect," and older signatures are "shadowed." +For each certificate, there is at most one "active" direct key signature, for each User ID at most one active self-certification and for each subkey exactly one subkey binding. + +## Complexity of the packet format + +OpenPGP certificates can contain complex preference settings. Additionally, the OpenPGP packet format allows a lot of flexibility when storing certificates in TPK format. + +User ID packets, for example, do not have a fixed position in a TPK. This means an attacker (or an implementation-internal certificate canonicalization procedure) can change the order in which User IDs appear in the certificate's packet sequence. + +As a concrete example, consider a certificate with multiple User IDs, all marked as primary. Or similarly, a certificate with multiple User IDs of which none is marked as primary. +Clients might apply different heuristics to figure out which User ID actually qualifies as the primary User ID here. + +Such subtle changes to the representation of a certificate can lead to different preference settings being deduced, by different OpenPGP implementations. diff --git a/book/source/armor.md b/book/source/armor.md new file mode 100644 index 0000000..e85e026 --- /dev/null +++ b/book/source/armor.md @@ -0,0 +1,95 @@ + + +# ASCII armor + +The native format of OpenPGP data is binary. + +However, in many use cases it is customary to use OpenPGP data in a non-binary encoding called "ASCII armor." For example, ASCII armored OpenPGP data is often used in email, for encrypted messages or for signatures. + +## Mechanism + +OpenPGP's ASCII armor mechanism consists of: + +- An [armor header line](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-armor-header-line) +- Optional [armor headers](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-armor-headers) that can contain additional metadata +- The [base64 encoded](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-base64-conversions) OpenPGP data +- An [optional checksum](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-optional-checksum) for this data +- An [armor tail line](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-armor-tail-line) (or footer) that matches the header line + +## Example + +In the chapter [](zoom/certificates), we take a look at a very minimal variant of Alice's certificate. In ASCII armored form, the certificate is 388 bytes long, and looks like this: + +```text +$ cat alice_minimal.pub +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xioGZRbqphsAAAAgUyTpQ6+rFfdu1bUSmHlpzRtdEGXr50Liq0f0hrOuZT7CtgYf +GwoAAAA9BYJlFuqmBYkFpI+9AwsJBwMVCggCmwECHgEiIQaqoYy7JUaFxYNYMgVj +/Te2fzMA+fsOxFc3jNKfECaYswAAAAoJEKqhjLslRoXFZ0cgouNjgeNr0E9W18g4 +gAIl6FM5SWuQxg12j0S07ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L ++BXIoY2sIEQrLd4TAEEy0BA8aQZTPEmMdiOCM1QB+V+BQZAO +=5nyq +-----END PGP PUBLIC KEY BLOCK----- +``` + +In this example, the *armor header line* uses the *header line text* `BEGIN PGP PUBLIC KEY BLOCK` (referring to the certificate data using the term *PGP public key*). Note that the matching footer uses the text `END PGP PUBLIC KEY BLOCK`. + +There are no *armor headers* with additional metadata in this example. The base64 encoded message spans five lines, and is followed by a CRC24 checksum line with the content `=5nyq`. + +The armored format is convenient when transferring OpenPGP data (like this certificate) in email Text. It is a robust format for manual copying and pasting, etc. + +### Contrast with binary OpenPGP data + +Using the `sq` commandline tool, we can compare this with the same OpenPGP data in binary form: + +```text +$ sq dearmor alice_minimal.pub > alice_minimal.pub.bin +``` + +The resulting binary representation of the same data comprises 228 bytes. We can look at its hexdump: + +```text +$ hexdump -C alice_minimal.pub.bin +00000000 c6 2a 06 65 16 ea a6 1b 00 00 00 20 53 24 e9 43 |.*.e....... S$.C| +00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65 |....n....yi..].e| +00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e c2 b6 06 1f |..B..G....e>....| +00000030 1b 0a 00 00 00 3d 05 82 65 16 ea a6 05 89 05 a4 |.....=..e.......| +00000040 8f bd 03 0b 09 07 03 15 0a 08 02 9b 01 02 1e 01 |................| +00000050 22 21 06 aa a1 8c bb 25 46 85 c5 83 58 32 05 63 |"!.....%F...X2.c| +00000060 fd 37 b6 7f 33 00 f9 fb 0e c4 57 37 8c d2 9f 10 |.7..3.....W7....| +00000070 26 98 b3 00 00 00 0a 09 10 aa a1 8c bb 25 46 85 |&............%F.| +00000080 c5 67 47 20 a2 e3 63 81 e3 6b d0 4f 56 d7 c8 38 |.gG ..c..k.OV..8| +00000090 80 02 25 e8 53 39 49 6b 90 c6 0d 76 8f 44 b4 ec |..%.S9Ik...v.D..| +000000a0 4c 42 38 8e 4d 3d 10 c2 ad 29 c0 57 ce 66 01 73 |LB8.M=...).W.f.s| +000000b0 b3 78 81 9e 89 52 cf 43 8d 28 11 a9 77 09 7f cb |.x...R.C.(..w...| +000000c0 f8 15 c8 a1 8d ac 20 44 2b 2d de 13 00 41 32 d0 |...... D+-...A2.| +000000d0 10 3c 69 06 53 3c 49 8c 76 23 82 33 54 01 f9 5f |. + +# Appendix A: OpenPGP artifacts + +(alice-priv)= +## Alice's OpenPGP key + +```text +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3 +Comment: + +xUsGZRbqphsAAAAgUyTpQ6+rFfdu1bUSmHlpzRtdEGXr50Liq0f0hrOuZT4A7+GZ +tV8R+6qT6CadO7ItciB9/71C3UvpozaBO6XMz/vCtgYfGwoAAAA9BYJlFuqmBYkF +pI+9AwsJBwMVCggCmwECHgEiIQaqoYy7JUaFxYNYMgVj/Te2fzMA+fsOxFc3jNKf +ECaYswAAAAoJEKqhjLslRoXFZ0cgouNjgeNr0E9W18g4gAIl6FM5SWuQxg12j0S0 +7ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L+BXIoY2sIEQrLd4TAEEy +0BA8aQZTPEmMdiOCM1QB+V+BQZAOzRM8YWxpY2VAZXhhbXBsZS5vcmc+wrkGExsK +AAAAQAWCZRbqpgWJBaSPvQMLCQcDFQoIApkBApsBAh4BIiEGqqGMuyVGhcWDWDIF +Y/03tn8zAPn7DsRXN4zSnxAmmLMAAAAKCRCqoYy7JUaFxdu4IIotb9pnNbxdBHe0 +nWeobsXWiFNf4u/5Zgi/wuDbwFYN69QspRkBD7om0IKiz1zreqly2fOyZgeLsro9 +t4nkdgRuNSQrJymDvpGceGrMtNVpR3YsKdZUv0MZBP9TmMDVC8dLBmUW6qYZAAAA +INGuh9fMQq+ZNMXCXMr6t0rIQ/yGNSpGAfPMAPVKCT4/ACh9zdomFjeN6iTHzudw +x5vlbwrJd/u9I0FzyVdav3xMwqsGGBsKAAAAMgWCZRbqpgWJBaSPvQKbDCIhBqqh +jLslRoXFg1gyBWP9N7Z/MwD5+w7EVzeM0p8QJpizAAAACgkQqqGMuyVGhcUiiSAL +DIm1qxXjf+RNuafvcUgUO6smXzR/bUgun3hIWG2a+22y2y+XjsgS/Fd/harRWbyA +QAu+LvDhIy2/S3F+0OTANuTSz7KftKhPPiohiXTCM1WvrEE2GytgCfLZGfRBEgvH +SwZlFuqmGwAAACAzjNT1GnM5787WDyGNoFiiPD1EqFnpEx8SnG8Z0D1AoAAOy9HJ +vIGCqncfqBKmKnSkIMF0dvOGJPuoJaVi3daikcLAhQYYGwoAAADMBYJlFuqmBYkF +pI+9ApsCmaAGGRsKAAAAKQWCZRbqpiIhBtB7JOyRoU3SQKwtU+bIqeBUlJpBIi6n +OFdu0Zyuo9yZAAAAAFNlIEIDrQzb/LWamKYVJ+QRXvXyoD287Y2UJ0EJ9jxL+Irl +r3PhfVQHQD/zKTTC52BWpeFDywi6Zv6LJs7ny6U6RrulyF3kat6uSeE+B7/EnpgU +Lz7F9wE+Pk/2GCqsve1SDCIhBqqhjLslRoXFg1gyBWP9N7Z/MwD5+w7EVzeM0p8Q +JpizAAAACgkQqqGMuyVGhcWEHCAjPbJJ8wJLCJOvugiJ8OCRD6siJqqzVlcw6pUp +BmBvAL5EoZU4qWs6PlHwVQmx4pGpF4b69R4/0ChGPM5uiBQ3Muw9+sYByuWpS7dj +lMMNkqvc+iNQcWAxpnPIM1qc2QrHSwZlFuqmGwAAACDwBi/5Muf1wpuajKjKJAxR +OVLySBVJj9b62QyLOJg0xwDYFSvx1cQi8FF4tCtpn89N0vMTmG7fQoW0DVOI1u0K +tcKrBhgbCgAAADIFgmUW6qYFiQWkj70CmyAiIQaqoYy7JUaFxYNYMgVj/Te2fzMA ++fsOxFc3jNKfECaYswAAAAoJEKqhjLslRoXF3Zgg/R2/mYLb/DpRSKA2ykKvFiRM +HLb8jRg6WGcr+XPuQbgdalxjFetO9EbZjOuYl3Jok/zObOgK7bCEoVEs9/UHR/K+ +FcsHp6K860qG87pDlk2saQIwzXPmQcQvLokbeQMB +=DfxN +-----END PGP PRIVATE KEY BLOCK----- +``` + +(bob-priv)= +## Bob's OpenPGP key + +Bob uses passphrase-protected secret key packets. His passphrase is `password`: + +```text +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: BB28 9FB7 A68D BFA8 C384 CCCD E205 8E02 D9C6 CD2F 3C7C 56AE 7FB5 3D97 1170 BA83 +Comment: Bob Baker + +xYYGZSlULBsAAAAgR+fC3FiOy/3ySZBmrqo2ZsqpVS1xiHwlkcN1cx0HYNb+FgkU +BDt/Sw6sizliWrTUvWkEE8cBBBUh/7788cWcdZ0f0fgZ5/1HVeNp/y/oUkhmA9M3 +UnsFy/qx+BP39iCI1vWLxLRRUrpt+Xwa7p/msftj0cpKPzPZLMkmRsK2Bh8bCgAA +AD0FgmUpVCwFiQWkj70DCwkHAxUKCAKbAQIeASIhBrson7emjb+ow4TMzeIFjgLZ +xs0vPHxWrn+1PZcRcLqDAAAACgkQuyift6aNv6hmsCBGbcyDxHuoq4DTmpzhwxCo +Pq37LydspnltmjW6ZlSTLOc7dt+MiSxAUIqH9i0CQVV9cyQfc0Gi7YzjnvQ9RxcZ +raou5c0b126fZ6Rt2vzLHICGw3v7dpCAnR0Y2lUvaAXNG0JvYiBCYWtlciA8Ym9i +QGV4YW1wbGUub3JnPsK5BhMbCgAAAEAFgmUpVCwFiQWkj70DCwkHAxUKCAKZAQKb +AQIeASIhBrson7emjb+ow4TMzeIFjgLZxs0vPHxWrn+1PZcRcLqDAAAACgkQuyif +t6aNv6h76CB+0O5ke9ijamCxuAz9FHaMDN+l+mQrTYFTLCpGpkWIta+yHy3YdGog +5o5KzDQPrSART32y2dRKQci/49rafLDEqHfPzhEPwwcKWjJxpEpA+AUR+r0WuAh0 +dRzT5vjPJwLHhgZlKVQsGQAAACAx8dR3SX4a2pudy0Fkzz8IkVhI+iIICfcKe8FC +HBUOFP4WCRQEw0VAyFbfmLAChDiHM714gQEEFcXLCpUyt+CPel5FO0wVibtGYRHr +pFEH/iCz7VYAup7lgerjiqTWdla37S+cAra9XduruJUZ3XS+L4bhYZTiCe2Jn8Fd +wqsGGBsKAAAAMgWCZSlULAWJBaSPvQKbDCIhBrson7emjb+ow4TMzeIFjgLZxs0v +PHxWrn+1PZcRcLqDAAAACgkQuyift6aNv6ggfiDu7s2cKnNx1vn17XV99XFo+DVe +Z/MQBOIbZ7bQz2ufS4PIjnC62/oybvC+GeNcnD8kOYfwtxPtl6DQdbpHYyqgNO21 +RMq9oNvei4tKmh7gg6jXGrmWKT6yOIPZyqpQUg/HhgZlKVQsGwAAACAGelHxA+Uz +4M73R7YTo7Xjg3KKoLmc/BYWA/QZ3noQNP4WCRQEG4OjK8N9PVQioBCJ848J8QEE +FRjFFaC6UN5LB6wyCqvozRo/e069dUiwlnYssBNPINsXQiBPcxmoSbyxVRF7LR9G +BZy9/bVQw9ZyPKtbvBQEQKy4m1qvwsCFBhgbCgAAAMwFgmUpVCwFiQWkj70CmwKZ +oAYZGwoAAAApBYJlKVQsIiEGLJuY+NkqRYws6tuzQ2Bff3TWsiqA7IzIPzpNxQjJ ++pUAAAAA6LUg9nuvXbKHUCoGMAdiVV/ttYcO583925/m/T3nC/CNNShitGiBRNAp +HnGyQKVkROyzYznyA9jCF+Ck1jeOCb5nQ7PwxHxRuP4ZG0uRN23pQh4eM2F7V/2F +iOkRF9lAM0AEIiEGuyift6aNv6jDhMzN4gWOAtnGzS88fFauf7U9lxFwuoMAAAAK +CRC7KJ+3po2/qBhPIIPtGEG7TzgO0gXQjhlx9hNBdKxAzScMwRT7oAT3RZrG5hGH +oyvf2n86URceCnfYSwZSOij7CfD0ZJgDmNmvJ5//yx7I7M4YCCheAd5er3/eaF6O +VJt3Ui/pv5VuXLTRC8eGBmUpVCwbAAAAIFnzWg9EBmVGFMUClhrtT5DNdCf+A4OQ +90WbiTHnseuR/hYJFAT5Ylewq+lINPw46gwA5Z6eAQQViAjElYeZobbZ+D001l/M +QvHaiEbEIXadwP3bbjoM43rFoP+p8cNYYECYAL8sx34uIxeixwrL6aOZ8j6Y1zbP +C8jTYNrCqwYYGwoAAAAyBYJlKVQsBYkFpI+9ApsgIiEGuyift6aNv6jDhMzN4gWO +AtnGzS88fFauf7U9lxFwuoMAAAAKCRC7KJ+3po2/qLHdID+av7QZ75Fq4v9YVHpc +wVXtKDX+MOKJM4xz7RvBWErH2xWyqikNZQVuzz/WqOVH/nT+BcqmLWAe3yjrTE4B +hSfrR38Nk23E4Bu4HobVrg7rlMU6SKHRWKeX/iSUmr6GDA== +=UZBq +-----END PGP PRIVATE KEY BLOCK----- +``` diff --git a/book/source/certificates.md b/book/source/certificates.md new file mode 100644 index 0000000..345c75f --- /dev/null +++ b/book/source/certificates.md @@ -0,0 +1,294 @@ + + +# Certificates + +OpenPGP fundamentally hinges on the concept of "{term}`OpenPGP certificates`," also known as "{term}`OpenPGP public keys`." These {term}`certificates` are complex data structures essential for {term}`identity verification`, data encryption, and {term}`digital signatures`. Understanding their structure and function is pivotal to effectively applying the OpenPGP standard. + +An {term}`OpenPGP certificate`, by definition, does not contain {term}`private key material`. + +Fundamentally, the effective management of {term}`certificates` and a thorough grasp of their {term}`authentication` and {term}`trust models` are crucial for proficient OpenPGP usage. Although this document offers just a brief overview of these aspects, they form a fundamental part of the broader OpenPGP framework and warrant further study. + +- For an in-depth exploration of OpenPGP's {term}`private key material`, refer to [](/private_keys). This chapter provides essential insights into {term}`private key` management and security practices. + +- The bindings that link the {term}`components` of a {term}`certificate` are comprehensively discussed in [](/signing_components), offering a deeper understanding of {term}`certificate` structure and integrity. + +- Finally, our chapter [](zoom/certificates) discusses the internal structure of {term}`certificates` in detail. + +## Terminology: Understanding "keys" + +The term "{term}`(cryptographic) keys`" is central to grasping the concept of {term}`OpenPGP certificates`. However, it can refer to different entities, making it a potentially confusing term. Let's clarify those differences. + +### Public vs. private keys + +The term "{term}`key`," without additional context, can refer to either public or private {term}`asymmetric` key material. Additionally, {term}`symmetric` keys may be used in OpenPGP to encrypt {term}`private key material`, adding a layer of security and complexity. + +(layers-of-keys-in-openpgp)= +### Layers of keys in OpenPGP + +In OpenPGP, the term "{term}`key`" may refer to three distinct layers, each serving a unique purpose: + +1. A (bare) ["cryptographic key"](asymmetric-key-pair) comprises the private and/or public parameters forming a key. For instance, in the case of an RSA {term}`private key`, the key consists of the exponent `d` along with the prime numbers `p` and `q`. +2. An OpenPGP *{term}`component key`* includes either an "{term}`OpenPGP primary key`" or an "{term}`OpenPGP subkey`." It is a building block of an {term}`OpenPGP certificate`, consisting of a cryptographic keypair coupled with some invariant {term}`metadata`, such as key {term}`creation time`. +3. An "{term}`OpenPGP certificate`" (or "OpenPGP key") consists of several {term}`component keys`, {term}`identity components`, and other elements. These {term}`certificates` are dynamic, evolving over time as {term}`components` are added, {term}`expire`, or are marked as {term}`invalid`. + +The following section will delve into the OpenPGP-specific layers (2 and 3) to provide a clearer understanding of their roles within {term}`OpenPGP certificates`. + +## Structure of OpenPGP certificates + +An {term}`OpenPGP certificate` (or "{term}`OpenPGP key`") is a collection of an arbitrary number of elements[^packets]: + +[^packets]: In technical terms, the elements of an {term}`OpenPGP certificate` are a collection of "{term}`packets`." Each {term}`component key` and {term}`identity component` is internally represented as a {term}`packet`. Another common type of {term}`packet` is the "{term}`signature`" {term}`packet`, which connect the {term}`components` of a {term}`certificate`. + +- {term}`Component keys` +- {term}`Identity components` +- Additional {term}`metadata`, including connections between the {term}`certificate`'s {term}`components` + +This documentation collectively refers to {term}`component keys` and {term}`identity components` as "the {term}`components` of a {term}`certificate`." + +```{figure} plain_svg/Components_of_an_OpenPGP_Certificate.svg +:name: fig-openpgp-certificate-components +:alt: Depicts a box with white background and the title "OpenPGP certificate". In the box several other boxes and accompanying texts, representing component keys and User IDs, are shown. There are three component keys boxes with a green frame, each with a dotted lower-left section, that shows the text "key creation time" and the green public key symbol in the lower right area. All three have a title, a unique fingerprint below the box and a unique capability keyword, perpendicular to the box on the right side. The top-most component key box has a light-green background, with the title "Component Key (primary)" and capability keyword "certification". The second-to-top component key box has a white background, with the title "Component Key" and capability keyword "encryption". The lowest component key box has a white background, with the title "Component Key" and capability keyword "signing". There are two User ID boxes, each with a black frame, open to top left and lower right corner. Both boxes have a user icon on the top left side, the title "User ID" on the top right side and a User ID string at the bottom. The top box has "Alice Adams " and the lower box has "Alice" as User ID string. + +Typical {term}`components` in an {term}`OpenPGP certificate` +``` + +Every element in an {term}`OpenPGP certificate` revolves around a central {term}`component`: the *{term}`OpenPGP primary key`*. The primary key acts as a personal *{term}`certification authority`* ({term}`CA`) for the {term}`certificate`'s owner, enabling cryptographic statements regarding {term}`subkeys`, {term}`identities`, {term}`expiration`, {term}`revocation`, and more. + +```{note} +{term}`OpenPGP certificates` tend to have a long lifespan, with the potential for modifications (typically by their owner) over time. {term}`Components` may be added or {term}`invalidated` throughout a {term}`certificate`'s lifetime. However, once published, {term}`components` [cannot be removed](append-only) from {term}`certificates`. +``` + +(component-keys)= +## Component keys + +An {term}`OpenPGP certificate` usually contains multiple {term}`component keys`. {term}`Component keys` serve in one of two roles: either as an "{term}`OpenPGP primary key`" or as an "{term}`OpenPGP subkey`." + +{term}`OpenPGP component keys` logically consist of an [asymmetric cryptographic keypair](asymmetric-key-pair) and a creation timestamp. Once created, these attributes of a {term}`component key` remain fixed (for ECDH keys, two additional parameters are part of a {term}`component key`'s constitutive data[^ecdh-parameters]). + +[^ecdh-parameters]: For [ECDH](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-part-for-ecd) {term}`component keys`, two additional algorithm parameters are integral to the {term}`component key`'s constitutive and immutable properties. Those parameters specify a hash function and a {term}`symmetric` encryption algorithm. + +```{figure} plain_svg/Component_Key.svg +:name: fig-component-key +:alt: Depicts a box with white background and no title. In the box one other box is shown. The inner box has a green frame, with a dotted lower-left section, that shows the text "key creation time" and the green public key symbol, as well as the red-dotted private key symbol in the lower right area. In the top left of the inner box the text reads "Component Key." + +An {term}`OpenPGP component key` +``` + +{term}`Component keys` containing {term}`private key material` also include {term}`metadata` specifying the password protection scheme. This is another facet of {term}`metadata`, akin to the aforementioned creation timestamp and additional parameters for certain algorithms. However, this discussion focuses on {term}`OpenPGP certificates`, in which the {term}`component keys` contain only the public part of its cryptographic key data. For information on {term}`private keys` in OpenPGP, see [](private_keys). + +(fingerprint)= +### Fingerprint + +Each {term}`OpenPGP component key` possesses an *{term}`OpenPGP fingerprint`*. This {term}`fingerprint` is derived from the {term}`public key material`, the {term}`creation timestamp`, and, when relevant, the ECDH parameters. + +```{figure} plain_svg/Fingerprint.svg +:name: fig-fingerprint +:alt: Depicts a box with white background and the title "Fingerprint of an OpenPGP component key." Inside, another box with a green frame, the title "Component Key", the text "key creation time" on the lower left and a the green public key symbol on the lower right is shown. Below the component key box a fingerprint in a box with a light-yellow background and a yellow dotted line is depicted. The word "Fingerprint" is shown left of the box with the fingerprint and both are connected with a yellow dotted line. + +Every {term}`OpenPGP component key` is identifiable by a {term}`fingerprint`. +``` + +The {term}`fingerprint` of our example {term}`OpenPGP component key` is `C0A5 8384 A438 E5A1 4F73 7124 26A4 D45D BAEE F4A3 9E6B 30B0 9D55 13F9 78AC CA94`[^keyid]. + +[^keyid]: In OpenPGP version 4, the rightmost 64 bits were sometimes used as a shorter identifier, called "{term}`Key ID`." +For example, an OpenPGP version 4 {term}`certificate` with the {term}`fingerprint` `B3D2 7B09 FBA4 1235 2B41 8972 C8B8 6AC4 2455 4239` might be referenced by the 64-bit {term}`Key ID` `C8B8 6AC4 2455 4239` or formatted as `0xC8B86AC424554239`. +Historically, even shorter 32-bit identifiers were used, like this: `2455 4239`, or `0x24554239`. Such identifiers still appear in very old documents about PGP. However, [32-bit identifiers have been long deemed unfit for purpose](https://evil32.com/). At one point, 32-bit identifiers were called "short {term}`Key ID`," while 64-bit identifiers were referred to as "long Key ID." + +```{note} +In practice, the {term}`fingerprint` of a {term}`component key`, while not theoretically unique, functions effectively as a unique identifier. The use of a [cryptographic hash algorithm](cryptographic-hash) in generating {term}`fingerprints` makes the occurrence of two different {term}`component keys` with the same {term}`fingerprint` extremely unlikely[^finger-unique]. + ``` + +[^finger-unique]: For both {term}`OpenPGP version 6` and version 4, the likelihood of accidental occurrence of duplicate {term}`fingerprints` is negligible when {term}`key material` is generated based on an acceptable source of entropy. A separate question is if an attacker can purposely craft a second key with the same {term}`fingerprint` as a given pre-existing {term}`component key`. With the current state of the art, this is not possible for OpenPGP version 6 and version 4 keys. However, at the time of this writing, the SHA-1-based {term}`fingerprints` of OpenPGP version 4 are considered insufficiently strong at protecting against the generation of pairs of {term}`key material` with the same {term}`fingerprint`. + +(primary-key)= +### Primary key + +The {term}`OpenPGP primary key` is a {term}`component key` that serves a distinct, central role in an {term}`OpenPGP certificate`: + +- Its {term}`fingerprint` acts as an identifier for the entire {term}`OpenPGP certificate`. +- It facilitates lifecycle operations, such as adding or {term}`invalidating` {term}`subkeys` or {term}`identities` within a {term}`certificate`. + +```{admonition} Terminology +:class: note + +In the {term}`RFC`, the {term}`OpenPGP primary key` is occasionally referred to as "top-level key." Informally, it has also been termed the "{term}`master key`." +``` + +(subkeys)= +### Subkeys + +Modern {term}`OpenPGP certificates` typically include several {term}`subkeys` in addition to the {term}`primary key`, although these {term}`subkeys` are optional. + +While {term}`subkeys` have the same structural attributes as the {term}`primary key`, they fulfill different roles. {term}`Subkeys` are cryptographically linked with the {term}`primary key`, a relationship further discussed in {numref}`bind-subkey`. + +```{figure} plain_svg/Binding_Subkeys.svg +:name: fig-subkeys +:alt: Diagram depicting three component keys. The primary key is positioned at the top, designated for certification. Below it, connected by arrows, are two subkeys labeled as "for encryption" and "for signing," respectively. + +{term}`OpenPGP certificates` can contain multiple {term}`subkeys`. +``` + +(identity-components)= +## Identity components + +{term}`Identity components` in an {term}`OpenPGP certificate` are used by the {term}`certificate holder` to state that they are known by a certain identifier (like a name, or an email address). + +(user-ids)= +### User IDs in OpenPGP certificates + +{term}`OpenPGP certificates` can contain multiple [User IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#uid). Each {term}`User ID` associates the {term}`certificate` with an {term}`identity`. + +```{figure} plain_svg/Binding_a_UserID.svg +:name: fig-user-ids +:alt: Depicts a diagram with white background and the title "User IDs". Inside, a public primary component key for certification and a User ID is shown. A green arrow points from component key to User ID and is annotated with a signature. + +Relationship of {term}`User ID` to primary {term}`component key` in an {term}`OpenPGP certificate` +``` + +A typical {term}`User ID` {term}`identity` is a UTF-8-encoded string composed of a name and an email address. By convention, {term}`User IDs` align with the format described in [RFC2822](https://www.rfc-editor.org/rfc/rfc2822) as a *name-addr*. + +For further conventions on {term}`User IDs`, refer to the document [draft-dkg-openpgp-userid-conventions-00](https://datatracker.ietf.org/doc/draft-dkg-openpgp-userid-conventions/), dated 25 August 2023. + +**Split User IDs** + +One proposed variant for encoding {term}`identities` in {term}`User IDs` is to use ["split User IDs"](https://dkg.fifthhorseman.net/blog/2021-dkg-openpgp-transition.html#split-user-ids). Although uncommon, there are currently no significant technical barriers to implementing this format[^dkg-split]. + +[^dkg-split]: Historically, the OpenPGP ecosystem faced challenges in this context. For further details, refer to Daniel Kahn Gillmor's January 2019 article, ["What were Separated User IDs"](https://dkg.fifthhorseman.net/blog/2019-dkg-openpgp-transition.html#what-were-separated-user-ids). + +The rationale for split {term}`User IDs` lies in the distinction between a name and an email address, which represent two separate facets of an individual's {term}`identity`. Separating these elements simplifies the process for third parties tasked with certifying that an {term}`identity` is legitimately connected to a {term}`certificate`. + +Consider this scenario: A third party is confident about the email-based {term}`identity` of an individual (e.g.,``) and is willing to certify it. However, they might not have sufficient knowledge about the person's name-based {term}`identity` (e.g., `Alice Adams`), so are unwilling to extend the same level of {term}`certification`. Split {term}`User IDs` address this dichotomy by allowing distinct {term}`certification` processes for each type of {term}`identity`. + +(primary-user-id)= +### Implications of the Primary User ID + +Within a {term}`certificate`, a specific {term}`User ID` is designated as the [Primary User ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-primary-user-id). + +Each {term}`User ID` carries associated preference settings, such as preferred encryption algorithms, which is detailed in {numref}`zoom-user-id`). When a {term}`certificate` is used in the context of a specific {term}`identity`, then the preferences associated with that {term}`identity component` are used. When a {term}`certificate` is used without reference to a specific {term}`identity`, the preferences associated with the {term}`direct key signature`, or the {term}`primary User ID` take precedence by default. + +The {term}`primary User ID` was historically the main store for preferences that apply to the {term}`certificate` as a whole. For more on this, see {ref}`primary-metadata`. + +(user-attributes)= +### User attributes in OpenPGP +While +[user attributes](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#user-attribute-packet) are similar to {term}`User IDs`, they are less commonly used. + +Currently, the OpenPGP standard prescribes only one format to be stored in user attributes: an [image](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-the-image-attribute-subpack) in JPEG format. Typically, this image represents the key owner, although it is not required. + +## Linking the components + +To form an {term}`OpenPGP certificate`, individual {term}`components` are interconnected by the {term}`certificate holder` using their OpenPGP software. Within OpenPGP, this process is termed "binding", as in "a {term}`subkey` is bound to the {term}`primary key`." These bindings are realized using cryptographic {term}`signatures`. An in-depth discussion of this topic can be found in [](signing_components). + +In very abstract terms, the {term}`primary key` of a {term}`certificate` acts as a root of trust or "{term}`certification authority`." It is responsible for: + +- issuing {term}`signatures` that express the {term}`certificate holder`'s intent to use specific {term}`subkeys` or {term}`identity components`; +- conducting other lifecycle operations, including setting {term}`expiration` dates and marking {term}`components` as {term}`invalidated` or "`revoked`." + +By binding {term}`components` using digital {term}`signatures`, recipients of an {term}`OpenPGP certificate` need only {term}`validate` the {term}`authenticity` of the {term}`primary key` to use for their communication partner. Traditionally, this is done by manually verifying the *{term}`fingerprint`* of the {term}`primary key`. Once the {term}`validity` of the {term}`primary key` is confirmed, the {term}`validity` of the remaining {term}`components` can be automatically assessed by the user's OpenPGP software. Generally, {term}`components` are {term}`valid` parts of a {term}`certificate` if there is a statement signed by the {term}`certificate`'s {term}`primary key` endorsing this {term}`validity`. + +(metadata-in-certificates)= +## Metadata in certificates + +{term}`OpenPGP certificates`, their {term}`component keys`, and {term}`identities` possess {term}`metadata` that is not stored within the {term}`components` it pertains to. Instead, this {term}`metadata` is stored within signature packets, which are integral to the structure of an OpenPGP certificate. + +Key attributes, such as {term}`capabilities` (like *signing* or *encryption*) and {term}`expiration times`, are examples of {term}`metadata` not stored in the {term}`component key` data. How this {term}`metadata` is stored depends on the {term}`component`: + +- **{term}`Primary key` {term}`metadata`** is defined either through a {term}`direct key signature` on the {term}`primary key` (preferred in OpenPGP version 6), or by associating the {term}`metadata` with the [Primary User ID](primary-user-id). + +- **{term}`Subkey` {term}`metadata`** is defined within the [subkey binding signature](recipe-binding-subkeys) that links the {term}`subkey` to the {term}`certificate`. + +- **{term}`Identity component` {term}`metadata`** is associated via the [certifying self-signature](bind-identity) that links the {term}`identity` (usually in the form of a {term}`User ID`) to the {term}`certificate`. + +It is crucial to note that the {term}`components` of an {term}`OpenPGP certificate` remain static after their creation. The use of {term}`signatures` to store {term}`metadata` allows for subsequent modifications without altering the original {term}`component`. For instance, a {term}`certificate holder` can update the {term}`expiration time` of a {term}`component` by issuing a new, superseding {term}`signature`. + +```{figure} plain_svg/Primary_key_metadata.svg +:name: fig-primary-metadata +:alt: Depicts a direct key signature, associated with a primary component key. + +{term}`Metadata` can be associated with the {term}`primary key` using a *{term}`direct key signature`*. +``` + +(key-flags)= +### Defining operational capabilities of component keys with key flags + +Each {term}`component key` has a set of ["key flags"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#key-flags) that delineate the operations a key can perform. + +Commonly used {term}`key flags` include: + +- **{term}`Certification`**: enables issuing third-party {term}`certifications` +- **{term}`Signing`**: allows the key to sign data +- **{term}`Encryption`**: allows the key to encrypt data +- **{term}`Authentication`**: primarily used for SSH authentication[^auth-flag] + +[^auth-flag]: It's important to note that the function of the [authentication](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-authentication-via-digital-) {term}`key flag` is unrelated to the {term}`authentication` process used in certifying OpenPGP {term}`identities` and linking them to {term}`certificate`. Rather, this flag indicates a mechanism that uses {term}`cryptographic signatures` to confirm control of {term}`private key material` with a remote system. + +```{note} +Distinct {term}`component keys` handle specific operations. Only the {term}`primary key` can be used for {term}`certification`, although it can have additional {term}`capabilities`. {term}`Subkeys` can be used for signing, encryption, and authentication but cannot have the {term}`certification` {term}`capability`. A {term}`component key` can technically have multiple {term}`capabilities`. It is considered good practice, however, to [use separate keys for each capability](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-10.1.5-7). + +Notably, in many algorithms, encryption and signing-related functionalities (i.e., {term}`certification`, {term}`signing`, {term}`authentication`) are mutually exclusive, because the algorithms only support one of those two families of operations[^key-flag-sharing]. +``` + +[^key-flag-sharing]: With ECC algorithms, it's impossible to combine {term}`encryption` functions with those intended for {term}`signing`. For example, ed25519 is specifically used for {term}`signing`; cv25519 is designated for {term}`encryption`. + +(preferences-features)= +### Algorithm preferences and feature signaling + +OpenPGP incorporates significant ["cryptographic agility"](https://en.wikipedia.org/wiki/Cryptographic_agility). It doesn't rely on a single fixed set of algorithms. Instead, it defines a suite of cryptographic primitives from which users (or their applications) can choose. + +This agility facilitates the easy adoption of new cryptographic primitives into the standard, allowing for a seamless transition. Users can gradually migrate to new cryptographic mechanisms without disruption. + +However, this approach requires that OpenPGP software determine the cryptographic mechanisms that a set of communication partners can handle and prefer. OpenPGP employs several mechanisms for this purpose, which allow negotiation between sender and recipient. It's important to note that OpenPGP is not an online scheme; thus, this negotiation is effectively one-way. The active party interprets the preferences expressed in the {term}`certificate` of the passive party. + +Negotiation mechanisms in OpenPGP include: + +- [Preferred hash algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#preferred-hashes-subpacket) +- [Preferred symmetric ciphers for v1 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#preferred-v1-seipd) +- [Preferred AEAD ciphersuites](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#preferred-v2-seipd) +- [Features subpacket](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#features-subpacket) +- [Preferred compression algorithms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#preferred-compression-subpacket) + +Beyond these explicitly expressed preferences, implementations also deduce {term}`capabilities` of communication partners based on the version of the {term}`OpenPGP certificate` they possess. + +#### User ID-specific preferences + +As a starting point, a {term}`certificate` has a set of preferences that apply generally. These are defined either in a {term}`direct key signature`, or via the {term}`primary User ID` of the {term}`certificate`. + +Additionally, OpenPGP allows modeling {term}`User ID`-specific preferences. The idea is that a user may prefer a different suite of algorithms on their private email account compared to their work email account. Such {term}`identity`-specific preferences can be expressed on the certifying {term}`signatures` that bind {term}`User IDs` to a {term}`certificate`. + +## A typical OpenPGP certificate, revisited + +Following our review of how {term}`keys` and {term}`identity components` are linked, let's reexamine the {term}`OpenPGP certificate` from {numref}`fig-openpgp-certificate-components`. Our focus now extends to all of its binding signatures and the {term}`direct key signature` that contains {term}`metadata` for the full {term}`certificate`: + +```{figure} plain_svg/OpenPGP_Certificate.svg +:name: fig-openpgp-certificate +:alt: Depicts an OpenPGP certificate, including a set of components, binding signatures, and a direct key signature on the primary key. + +This shows a typical {term}`OpenPGP certificate`, including binding {term}`signatures` for all of its {term}`components`, and a {term}`signature` that associates {term}`metadata` with the {term}`primary key`. +``` + +(revocations)= +## Revocations + +When a {term}`certificate holder` needs to {term}`invalidate` certain {term}`components` of their {term}`certificate`, or even the entire {term}`certificate`, they accomplish this through "{term}`revocation`." {term}`Revoking` the {term}`primary key` renders the entire {term}`certificate` {term}`invalid`. + +Notably, {term}`revocations` are not the only means by which {term}`components` can become {term}`invalid`. Other factors, such as the passing of a {term}`component`'s {term}`expiration time`, can also render {term}`components` {term}`invalid`. + +For more detailed information on {term}`revoking` specific {term}`components` of a {term}`certificate`, see the section on {ref}`self-revocations`. + +(third-party-identity-certifications)= +## Third-party (identity) certifications + +Since its inception, {term}`third-party identity certifications` have been a cornerstone of the OpenPGP ecosystem. The original PGP designers, starting with Phil Zimmermann, advocated for decentralized {term}`trust models` over reliance on centralized authorities. This decentralized approach in OpenPGP is known as the ["Web of Trust."](wot) + +{term}`Third-party certifications` are statements by OpenPGP users confirming that a user with a specific {term}`identity` is the owner of a particular {term}`OpenPGP certificate`. + +For example, Bob's OpenPGP software may issue a {term}`certification` that Bob has checked that the {term}`User ID` `Alice Adams ` and the {term}`certificate` with the {term}`fingerprint` `AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3` are legitimately linked. + +Take, for instance, a scenario where Bob's OpenPGP software issues a {term}`certification` confirming as legitimate the link between the {term}`User ID` `Alice Adams ` and the {term}`certificate` bearing the {term}`fingerprint` `AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3`. + +This process assumes that Bob knows the person known as `Alice Adams` and is confident that `alice@example.org` is indeed Alice's email address. Bob also verifies that the {term}`certificate` his OpenPGP software associates with Alice matches the one Alice uses. In essence, both users must have a {term}`certificate` for Alice with an identical {term}`fingerprint`. In OpenPGP version 6, manual {term}`fingerprint` comparison by end-users is discouraged, with a replacement {term}`verification` mechanism still under development. The {term}`verification` process must occur over a sufficiently secure channel, such as an end-to-end encrypted video call or a face-to-face meeting. + +For more on third-party {term}`certifications`, see {ref}`third-party-certifications`. diff --git a/book/source/compression.md b/book/source/compression.md new file mode 100644 index 0000000..a7b70b0 --- /dev/null +++ b/book/source/compression.md @@ -0,0 +1,25 @@ + + +# Compression + +Optional compression of data is one element of OpenPGP's composable functionality. Compression within OpenPGP can be convenient to applications. + +In one use case, this functionality is particularly helpful: When encrypting a message, the encrypted output is by definition high-entropy, and cannot be compressed anymore - even if the plaintext message was low-entropy, and could have been compressed well (like, for example, a text-file). + + +This means that to use whatever potential for compression exists, the message must be compressed *before* encryption. OpenPGP offers an integrated compression mechanism to make this convenient (otherwise, messages would need to be compressed and decompressed before and after encryption, to achieve the same space-efficiency). + +## Decompression yields a 'wrapped' OpenPGP packet stream + +Compression in OpenPGP is a simple mechanism: A [Compressed Data packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-compressed-data-packet-type) acts as a compressed container for a series of OpenPGP packets. + +The compressed data packet consists of the specification of which compression algorithm is used, followed by a compressed representation of the contained data. + +The series of OpenPGP packets inside the Compressed Data packet can be handled like any stream of OpenPGP packets. + +## Typical usage + +Compressed data packets are often used inside [encrypted data packets](/encryption), or wrapping the data of an [inline-signed message](inline-signature). diff --git a/book/source/conf.py b/book/source/conf.py new file mode 100644 index 0000000..63de928 --- /dev/null +++ b/book/source/conf.py @@ -0,0 +1,110 @@ +# 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: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +from datetime import date + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'OpenPGP for application developers' +author = 'The "Notes on OpenPGP" project' +upstream_url = "https://codeberg.org/openpgp/notes" +license_url = "https://creativecommons.org/licenses/by-sa/4.0/" +copyright = f'{date.today().year}, {author}, CC-BY-SA-4.0' +version = "0.1" +suppress_warnings = [ + 'epub.unknown_project_files', +] +description = 'The essential OpenPGP guide for application developers. Learn the OpenPGP standard for cryptographic operations and how to implement it in your projects. Gain insights into digital signatures, key management, certificates, and more. Version agnostic.' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'myst_parser', + 'sphinxext.opengraph', +] +source_suffix = ['.md', '.rst'] + +templates_path = ['_templates'] +exclude_patterns = [] + +# number code-blocks, figures and tables, if they have a caption +numfig = True +# number figures in flat hierarchy +numfig_secnum_depth = 0 + +# format today as YYYY-MM-DD instead of language specific +today_fmt = "%Y-%m-%d" + +# -- Options for MyST-parser ------------------------------------------------- +# https://myst-parser.readthedocs.io/en/latest/configuration.html + +# we want to circumvent obscure warnings about footnotes following a heading: +# https://github.com/executablebooks/MyST-Parser/issues/352 +myst_footnote_transition = False + +# Enable definition lists +# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#syntax-definition-lists +myst_enable_extensions = [ + "deflist", +] + +# https://myst-parser.readthedocs.io/en/latest/configuration.html#setting-html-metadata +myst_html_meta = { + "description lang=en": description, + "keywords": "openpgp, cryptographic operations, data encryption, digital signatures, key management, identity verification, secure communication, pgp, cryptographic protocols, public key encryption, openpgp v4, openpgp v6, openpgp implementation", + "property=og:locale": "en_US" +} + +# -- Options for EPUB output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-epub-output + +epub_copyright = f'{date.today().year}, {author} ({upstream_url}), CC-BY-SA-4.0' +epub_cover = ('_static/epub/img/cover.png', 'cover.j2') +epub_description = description +epub_css_files = [ + 'epub/css/custom.css' +] +epub_basename = project.replace(" ", "_") + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'alabaster' +html_static_path = ['_static'] +html_css_files = [ + ('html/css/custom.css', {'priority': 1000}) +] + +html_favicon = '_static/html/img/favicon.ico' +html_logo = '_static/html/img/logo.svg' +html_show_sphinx = False +html_show_sourcelink = False +html_title = project + +# https://github.com/sphinx-doc/alabaster/blob/0.x/alabaster/theme.conf +html_theme_options = { + 'code_font_size': '9pt', + 'extra_nav_links': { + 'Sources on Codeberg': upstream_url, + 'Download EPUB': f'https://openpgp.dev/book/{epub_basename}.epub', + }, + 'show_relbars': 'yes', + 'show_powered_by': False, +} + +# https://github.com/wpilibsuite/sphinxext-opengraph#simple-config +ogp_site_url = 'https://openpgp.dev/book/' +ogp_image = '_static/html/img/logo.png' +ogp_type = 'book' + +ogp_custom_meta_tags = [ + f'', +] + diff --git a/book/source/cryptography.md b/book/source/cryptography.md new file mode 100644 index 0000000..33b20c9 --- /dev/null +++ b/book/source/cryptography.md @@ -0,0 +1,144 @@ + + +# Cryptographic concepts and terms + +(cryptographic-hash)= +## Cryptographic hash functions + +[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, a "hash digest," which is often abbreviated as either "digest" or "hash." A hash digest is also sometimes called a "(cryptographic) checksum." A hash digest acts like a unique identifier for the original data. + +Cryptographic hash functions have two important properties: + +- [**Pre-image resistance**](https://en.wikipedia.org/wiki/Preimage_attack): Given a hash digest, it should be very difficult to determine any data that matches this hash digest (including, but not limited to, the original data the hash represents). This property embodies the concept of a [one-way function](https://en.wikipedia.org/wiki/One-way_function) – a calculation that is easy to perform, but very hard to reverse. +- [**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 digest. + +(message-authentication-code)= +## Message authentication codes + +A [message authentication code](https://en.wikipedia.org/wiki/Message_authentication_code) (MAC), also known as an {term}`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 {term}`(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](protected-private-keys) chapter and the [SEIPDv2](seipd-v2) section of the encryption chapter. + +(symmetric-key-cryptography)= +## Symmetric-key cryptography + +[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. + +```{figure} plain_svg/symmetric_key.svg +:name: fig-symmetric-key +:alt: Depicts a box with a white background and the title "Symmetric key". In the box a single key symbol, rendered with full yellow line, is shown pointing to the right hand side. + +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-key cryptographic mechanisms are believed to be resilient against possible advances in quantum computing[^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). + +However, exchanging the required shared secret is a problem that needs to be solved separately. + +[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 + +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-12.html#name-secret-key-encryption), and +- for [password-protected data encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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, the ["Version 2 Symmetrically Encrypted Integrity Protected Data Packet Format"](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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-12.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) offers more than just confidentiality; it ensures data integrity too. + +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]: 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. + +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." + +(public-key-cryptography)= +## Public-key (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. + +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 verification, while the private key, kept confidential, is used for operations like decryption and signature creation. + +(asymmetric-key-pair)= +### Asymmetric cryptographic key pairs + +Throughout this document, we will frequently reference asymmetric cryptographic key pairs: + +```{figure} plain_svg/asymmetric_keypair.svg +:name: fig-asymmetric-keypair +:alt: Depicts a box with white background and the title "Asymmetric keypair". In the box two key symbols with text next to them are shown. The top key symbol is rendered using full green lines, points to the right hand side and has the accompanying text "Public key". The lower key symbol is rendered using dotted red lines, points to the left hand side and has the accompanying text "Private key". + +An asymmetric cryptographic key pair +``` + +Each key pair comprises two parts: the {term}`public key` and the {term}`private key`. For ease of identification in this documentation, the {term}`public key` will be shown in green and the private key in red. Additionally, {term}`public keys` are depicted with a solid border and pointing to the right, while {term}`private keys` are shown with a dotted border and pointing to the left. + +It's important to note that in many scenarios, only the {term}`public key` is exposed or used. These situations will be elaborated upon in subsequent sections of this document. + +```{figure} plain_svg/public_key.svg +:name: fig-public-key +:alt: Depicts a box with white background and the title "Public part of an asymmetric keypair". In the box one key symbol with text next to it is shown. The key symbol is rendered using full green lines, points to the right hand side and has the accompanying text "Public key". + +The public part of an asymmetric key pair +``` + +### Usage and terminology in OpenPGP + +OpenPGP extensively uses {term}`public-key cryptography` for encryption and digital signing operations. + +```{admonition} Terminology +:class: note + +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. + +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 fundamental mechanism of {term}`asymmetric cryptography`, providing secure, mathematical means to validate the {term}`authenticity`, integrity, and origin of digital messages and documents. + +In OpenPGP, digital signatures have diverse applications, extending beyond mere validation of a message's origin. They can signify various intents, including {term}`certification`, consent, acknowledgment, or even revocation by the signer. The multifaceted nature of "statements" conveyed through {term}`digital signatures` in cryptographic protocols is wide-ranging but crucial, allowing third parties to inspect/evaluate these statements for {term}`authenticity` and intended purpose. + +{term}`Digital signatures` in OpenPGP are used in two primary contexts: + +- [Data signatures](signing_data) +- [Signatures on components](/signing_components) + +(hybrid-cryptosystems)= +## Hybrid cryptosystems + +[Hybrid cryptosystems](https://en.wikipedia.org/wiki/Hybrid_cryptosystem) combine the use of {term}`symmetric` and {term}`asymmetric (public-key)` cryptography to capitalize on the strengths of each, namely {term}`symmetric cryptography`'s speed and efficiency and {term}`public-key cryptography`'s mechanism for secure key exchange. + +### Usage and terminology in OpenPGP + +OpenPGP uses a {term}`hybrid cryptosystem` for encryption. This approach involves generating unique shared secrets, known as "session keys," for each session. For detailed information on this topic, please refer to the chapters [](encryption) and [](decryption). diff --git a/book/source/decryption.md b/book/source/decryption.md new file mode 100644 index 0000000..f0991ef --- /dev/null +++ b/book/source/decryption.md @@ -0,0 +1,184 @@ + + +# Decryption + +Message decryption is the process of taking an encrypted message and recovering its plaintext. +This involves multiple steps. + +Implementations typically first process the PKESK and SKESK packets leading the SEIPD packet to identify \*ESK packets suitable for decryption. +A PKESK packet is suitable if it contains a recipient-Key ID matching a decryption (sub-) key of the user's certificate. +Typically, all \*ESK packets leading a SEIPD packet contain the same *session key* once decrypted. + +```{note} + +Anonymous-recipient PKESK packets contain a recipient-Key ID of `0`, so if no suitable non-anonymous PKESK was found, any anonymous PKESKs are tried with any available decryption (sub-) keys (see [](decryption-anonymous-recipient)). +``` + +If no suitable PKESK packets were found, SKESK packets are tried next, meaning the user is typically prompted to enter a decryption passphrase. + +Once any of these methods succeeded, the resulting *session key* is used to decrypt the SEIPD packet. + +## Passphrase-protected session key (SKESK) + +Decrypting a SKESK packet to recover the *session key* is done by performing the encryption steps in reverse, based on a user-provided passphrase. + +In both version 4 and version 6 of the SKESK packet, the user is prompted to enter a passphrase, which is passed through the S2K function described by the SKESK packet. +However, the subsequent steps of the procedure are different, as described in the following sections. + +### SKESK v4 + +Here, the result of the S2K function is a symmetric key, which is either used to decrypt the encrypted session key contained in the SKESK packet, or - less commonly - used as session key directly (see [](decryption-skesk4-direct-method)). + +```{note} + +The "direct method" where the result of the S2K function is directly used as session key is only applicable if only one SKESK packet is present. +``` + +```{figure} plain_svg/SKESKv4-decryption.svg +:name: fig-skeskv4-decryption +:alt: Diagram depicting how the S2K function is used to derive key symmetric key from the user-provided passphrase. This key is then either used directly as session key, or used to decrypt the encrypted session key. + +Decrypting the session key from a version 4 SKESK packet. +``` + +With version 4 SKESK packets, which are only used with version 1 SEIPD packets, the *session key* is used as *message key* without an intermediate derivation. + +(decryption-skesk4-direct-method)= +#### Direct-Method + +In version 4 of the SKESK packet, the encrypted session key is optional. A missing encrypted session key signals the use of the "direct-method," which means the result of passing the passphrase through the S2K function is directly used as the session key/message key. + +When the direct method is used, the symmetric cipher algorithm ID of the SKESK packet dictates the cipher algorithm used to decrypt the plaintext from the SEIPD packet. + +Otherwise, the cipher algorithm ID to decrypt the SEIPD packet was prefixed to the decrypted session key. + +Sanitizing this algorithm ID of the decrypted session key acts as a very early quick check to verify that the used passphrase was correct. For further validation of the session key, see [](decryption-seipd-quick-check). + + +### SKESK v6 + +With version 6 SKESK packets, the result of the passing the passphrase through the S2K function is used as *initial keying material* (IKM) to derive a symmetric *key encryption key* using HKDF as a key derivation function. The HKDF function doesn't use any salt in this step, and the *info* parameter is assembled from parameters of the SKESK packet. + +In the next step, this symmetric key is used to decrypt the *session key* using AEAD. +The AEAD function uses information from the associated SEIPD v2 packet as *additional data*. +The function is also salted using the SEIPD v2's salt. +The *AEAD Auth Tag* of the SKESK packet is used as authentication tag. + +The result is the *session key*. + +```{figure} plain_svg/SKESKv6-decryption.svg +:name: fig-skeskv6-decryption +:alt: Diagram depicting the complicated process of deriving the session key from a SKESK version 6 packet. + +Decrypting the session key from a version 6 SKESK packet. +``` + +## Key-protected session key (PKESK) + +More common than SKESK packets are PKESK packets which are used to protect the session key using an encryption key of the recipient. + +### PKESK v3 + +With version 3 PKESKs, the recipient's secret encryption (sub-) key is directly used to decrypt the encrypted *session key*. +The Key ID of the subkey to be used is recorded in the PKESKs key-id field. A value of `0` indicates an anonymous recipient (see [](decryption-anonymous-recipient)). + +To detect, which symmetric cipher is used to decrypt the SEIPD v1 packet later on, each public key algorithm uses a slightly different encoding to unpack the symmetric algorithm tag from the decrypted session key. See the respective sections[^rsa-spec] [^elgamal-spec] [^ecdh-spec] [^x25519-spec] [^x448-spec] of the standard. Typically, the cipher algorithm ID is prefixed to the actual session key. + +[^rsa-spec]: [Algorithm-Specific Fields for RSA encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-f) +[^elgamal-spec]: [Algorithm-Specific Fields for Elgamal encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-fo) +[^ecdh-spec]: [Algorithm-Specific Fields for ECDH encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-for) +[^x25519-spec]: [Algorithm-Specific Fields for X25519 encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-for-) +[^x448-spec]: [Algorithm-Specific Fields for X448 encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-for-x) + +```{figure} plain_svg/PKESKv3-decryption.svg +:name: fig-decryption-pkesk3 +:alt: Depicts, how the secret-key component of the users encryption subkey is directly used to decrypt the encrypted session key. + +Decrypting the session key from a version 3 PKESK packet. +``` + +### PKESK v6 + +The decryption of version 6 PKESK packets works quite similarly to version 3. + +```{figure} plain_svg/PKESKv6-decryption.svg +:name: fig-decryption-pkesk6 +:alt: Depicts, how the secret-key component of the users encryption subkey is directly used to decrypt the encrypted session key. + +Decrypting the session key from a version 6 PKESK packet. +``` + +Contrary to the version 3 PKESK, the encrypted session key within the version 6 PKESK does not contain the symmetric cipher algorithm used to decrypt the SEIPD packet. +Instead, this cipher algorithm ID is encoded inside the SEIPD v2 packet directly. + +## SEIPD (v1) + +Version 1 SEIPD packets MUST only be used with version 3 PKESK packets and/or version 4 SKESK packets. +Any other combinations are not allowed and MUST result in a broken message. + +```{note} +Since SEIPD version 1 is susceptible to downgrade attacks under certain scenarios, it is recommended to use SEIPD version 2 wherever possible. +``` + +To decrypt the contents of a version 1 SEIPD packet, the session key obtained in the previous step is used. +The cipher algorithm is either extracted from the decrypted session key (the algorithm ID is typically prefixed to the decrypted session key), or - in case of a SKESK packet using the direct-method - taken from the SKESKs cipher algorithm field. + +Once the cipher is initialized, the whole encrypted data from the SEIPD packet is decrypted. + +### Verifying the quick-check bytes + +To quickly verify that the correct session-key was used during decryption, bytes with index 14 and 15 are compared to those with index 16 and 17 (zero-indexed). +A mismatch of those pairs of bytes indicates that the wrong session-key was used and decryption is aborted. + +### Verifying the modification detection code (mdc) + +The contents of a SEIPDv1 packet are protected against unnoticed modification via the addition of a modification detection code. +This is done by calculating the SHA1 checksum of the entire decrypted plaintext, but excluding the last 20 bytes, which are the actual checksum computed by the sender. +Compare figure {numref}`fig-encryption-mdc`. + +The result is then compared to those last 20 bytes to detect modifications of the ciphertext. + +```{figure} plain_svg/SEIPDv1-decryption.svg +:name: fig-decryption-seipd1 +:alt: Depicts how the session key is used directly to decrypt the contents of the SEIPD packet. + +The contents of the SEIPD packet are decrypted using the session key as message key. +``` + +## SEIPD w/ AEAD (v2) + +Preferred mode. +Version 2 SEIPD packets MUST only be used with version 6 PKESK packets and/or version 6 SKESK packets. +Any other combinations are not allowed and MUST result in a broken message. + +Once the session key was obtained from a PKESK or SKESK, it is used to derive a *message key* and an IV. This is done by passing the session key through a salted HKDF function, where the salt is unique per message and obtained from the SEIPD packet. + +The result is split into the message key and first half of the IV. + +```{figure} plain_svg/SEIPDv2-decryption-mk-derivation.svg +:name: fig-decryption-seipd2-mk-derivation +:alt: Depicts how the session key is fed into a salted HKDF to derive both the message key and the first half of an IV. + +In a first step, a message key and half of an IV is derived from the session key. +``` + +Then, the contents of the SEIPDs encrypted data are split into chunks, which are processed sequentially. Each chunk is decrypted using AEAD with parameters from the SEIPD packet as *additional data*. +For each chunk, the chunk index starting at `0` is passed into the function as second half of the IV. + +All decrypted plaintext blocks are appended to form the result of the decryption process. + +After all blocks have been processed, in a final AEAD step, the total number of plaintext octets gets appended to the *additional data* and the final AEAD auth tag from the SEIPD packet is processed. + +```{figure} plain_svg/SEIPDv2-decryption-chunks.svg +:name: fig-decryption-seipd2-chunks +:alt: Depicts, how the message key and index-postfixed IV are used to decrypt each individual chunk of plaintext. + +Each chunk is decrypted using AEAD using the message key and an IV with appended chunk index. +``` + +## SED + +Legacy mode: may be decrypted, but not produced. diff --git a/book/source/encryption.md b/book/source/encryption.md new file mode 100644 index 0000000..0f9ae6a --- /dev/null +++ b/book/source/encryption.md @@ -0,0 +1,161 @@ + + +# Encryption + +[Encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-confidentiality-via-encrypt) is one of the core facilities of OpenPGP. It provides confidentiality. + +For an in-depth, packet-level view of encrypted data in OpenPGP, see [](/zoom/encryption). + +## Terminology + +| Term | Description | +|--------------|------------------------------------------------------------------------------------------------------------| +| SEIPD Packet | *Symmetrically Encrypted, Integrity Protected Data* packet; contains the encrypted message payload | +| SKESK Packet | *Symmetric-Key Encrypted Session Key* packet; contains or provides a passphrase-encrypted session key | +| PKESK Packet | *Public-Key Encrypted Session Key* packet; contains a session key encrypted using an asymmetric public key | +| Session Key | Symmetric encryption key, which is either used directly as - or to derive - the message key | +| Message Key | Symmetric encryption key used to encrypt the contents of the SEIPD packet | + +## High-Level overview of the message encryption process + +Encryption in OpenPGP is performed in two distinct steps: + +1. **Symmetric encryption**: The plaintext is encrypted based on a (secret) symmetric key, the [*session key*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-confidentiality-via-encrypt). The (potentially large) ciphertext only needs to be stored once, even if it is sent to multiple recipients. All recipients get access to the same shared *session key* to decrypt the message. +2. **Session key transmission**: For each recipient of the message, a packet that contains a protected copy of the session key is generated. + - Usually, the *session key* is encrypted to a public encryption component key of the recipient. + - Alternatively - or additionally - the *session key* may also be encrypted using a passphrase. This is a specialized and less commonly used mode of operation that doesn't require OpenPGP certificates. + +```{note} +Above, "plaintext" means one of: +- *Literal Data* packet, +- *Compressed Data* packet or a +- *signed message*. + +A *signed message*, in turn, is a packet sequence that either +- resembles an *inline-signed message* (a *Literal Data* packet sandwhiched between one or more *One-Pass-Signature* and their respective *Signature* packets), or a +- *prefixed-signed* message (one or more *Signature* packets followed by a single *Literal Data* packet). +``` + +## Encryption mechanism versions + +OpenPGP's encryption mechanisms have evolved over time. The RFC shows an [overview of encryption mechanisms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-10.3.2.1), and how they may be combined. + +Two generations of encryption mechanisms are currently relevant in OpenPGP, and will co-exist for the foreseeable future. + +The main difference between these lies in the symmetric part of the encryption mechanism, represented by versions 1 and 2 of the *Symmetrically Encrypted and Integrity Protected Data* packets (abbreviated as "SEIPD"). The two versions use different mechanisms to provide non-malleability. More on these below. + +Older, legacy encryption mechanisms exist in OpenPGP. However, those must not be used for encryption anymore. Messages encrypted using these legacy mechanisms may still be decrypted, although with caution. For more information, see the [decryption](/decryption) chapter. + +SEIPD packets are used in combination with two mechanisms that store *session keys*: + +- [Public-Key Encrypted Session Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-encrypted-sessio) (PKESK) packets and +- [Symmetric-Key Encrypted Session Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#skesk) (SKESK) packets. + +The typical combination of mechanisms for encryption in OpenPGP is a [hybrid cryptosystem](hybrid-cryptosystems), consisting of one or more [Public-Key Encrypted Session Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-encrypted-sessio) packets (PKESK), followed by a [Symmetrically Encrypted Integrity Protected Data](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetrically-encrypted-int) (SEIPD) packet. + +In this combination, an asymmetric cryptographic mechanism is used to protect a *session key* inside PKESK packets. The *session key*, in turn, is used to protect the plaintext using symmetric-key encryption in a SEIPD packet. + +## Encrypted session keys: PKESK, SKESK + +Encrypted session key (ESK) packets are a family of two mechanisms for securing symmetric key material: + +- [PKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-encrypted-sessio): Uses asymmetric OpenPGP key material to protect a session key, and +- [SKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetric-key-encrypted-ses): Uses passphrases to protect the symmetric key material, instead of OpenPGP asymmetric key material (this is less commonly used). + +An arbitrary number of PKESKs and SKESKs can be used in the same message. It is also possible to mix the two, resulting in a message which can be decrypted using either one of the designated OpenPGP keys or any of the passphrases used to encrypt the message. This is useful to make a message available to a number of known recipients, with the option to provide the passphrase to future recipients. + +### PKESK: Session key encrypted to an asymmetric OpenPGP key + +To encrypt an OpenPGP message for a recipient, the session key is encrypted to the recipient's public key. The resulting encrypted session key is packed into a PKESK packet, which holds essential metadata, like an identifier of the recipients encryption (sub)-key. + +This procedure is repeated for each recipient of the message, and all resulting PKESK packets are prepended to the SEIPD packet (see below) containing the actual message. + +Typically, the sender would also include themselves as a recipient, to be able to decrypt the message with their own key at a later point in time. + +### SKESK: Session key encrypted to a passphrase + +As an alternative (or augmentation) to PKESK packets, a message can also be encrypted to a symmetric passphrase. This is done using a SKESK packet, which uses an S2K mechanism to derive a symmetric key from a passphrase. This key is either used directly as the session key, or more commonly, used as a key-encapsulation-key (KEK) to encrypt the session key. + +Also see https://flowcrypt.com/docs/guide/send-and-receive/send-password-protected-emails.html + +As for protection of secret key material, it is important to choose appropriate S2K parameters when generating an SKESK packet. +The specification currently recommends to use either *Iterated and Salted S2K* or *Argon2*. + +## Symmetric encryption of data, SEIPD + +*Symmetrically Encrypted Integrity Protected Data* (SEIPD) packets represent the symmetric aspect of OpenPGP's encryption mechanism. The function of these packets is entirely independent of (asymmetric) OpenPGP keys. + +A SEIPD packet contains the actual payload: the ciphertext of the encrypted message. For a large encrypted message, the SEIPD packet will also be large. + +```{note} +SEIPD packets are the successor to the [Symmetrically Encrypted Data](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetrically-encrypted-dat) packet, which is obsolete. +``` + +Two versions of the SEIPD packet (differentiated by the version number) have been specified. Version 1, introduced in RFC4880, is used in OpenPGP v4 while SEIPD version 2 was introduced with OpenPGP v6. Both versions can be used with either OpenPGP v4 or v6 keys, although OpenPGP v4 keys need to announce support for SEIPD version 2 via the *Feature* signature subpacket. + +When decrypted, the data contained in a SEIPD packet forms an [OpenPGP message](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-openpgp-messages). That is, the decrypted data consists of a series of OpenPGP packets. + +In both versions of SEIPD, the decryptor must have obtained a *session key* in a previous step, before processing the SEIPD packet. Using this session key, the decryptor can decrypt the SEIPD packet and process the plaintext data that it contains. + +### v1 SEIPD, based on MDC + +The [version 1 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#version-one-seipd) mechanism is supported by all modern OpenPGP version 4 implementations. It was introduced in [RFC 4880](https://www.rfc-editor.org/rfc/rfc4880.html#section-5.13) as a replacement for the *SED* (Symmetrically Encrypted Data) packet. SEIPDv1 provides integrity protection of the ciphertext using a SHA-1 checksum of the plaintext as modification detection code. + +Version 1 SEIPD can only be combined with [version 3 PKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v3-pkesk) and/or [version 4 SKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v4-skesk) packets. + +In this version of the SEIPD packet, the session key is used directly as message key, meaning the payload is encrypted symmetrically using the session key. + +When communicating with a mix of recipients, some of whose OpenPGP software only supports OpenPGP version 4, then this mechanism must be used. + +```{figure} plain_svg/SEIPDv1-PKESK.svg +:name: fig-encryption-seipdv1-pkesk +:alt: Depicts a dotted hexagon labeled "Plaintext", from which a curved arrow passes another dotted hexagon "Session Key" and finally points to a "SEIPDv1" packet. Two more curved arrows originate from the session key and pass Alice' and Bob's encryption key, ending in two PKESK packets. + +With SEIPDv1, the session key is directly used as message key to encrypt the payload +``` + +(quick-check-and-mdc)= +#### Preparing the plaintext with quick check and modification detection code + +Before encrypting the plaintext, the data is modified by adding both a prepended "quick check", as well as an appended modification detection code. + +The quick check comprises of 16 randomly chosen bytes plus 2 bytes which are the last two of the 16 random bytes repeated. +This mechanism is useful to quickly check, whether the correct session key was used when decrypting the message. +These quick-check bytes are prepended to the plaintext. + +The modification detection code on the other hand is added to allow detection of unwanted modification of the ciphertext. +First, the two marker bytes `0xD3` and `0x14` are appended to the plaintext. Then, the SHA1 checksum of the entire plaintext including quick check and marker bytes is calculated and appended to the plaintext. + +```{figure} plain_svg/mdc.svg +:name: fig-encryption-mdc +:alt: Depicts, how the prior to encryption, the plaintext bytes are prepended with 18 quick check bytes and appended with 22 bytes of modification detection code. The quick check comprises of 16 random bytes plus 2 repeated bytes. The modification detection code starts with the marker bytes 0xD314, followed by the SHA1 checksum of the entire plaintext including quick check and marker bytes. + +The plaintext inside of a SEIPDv1 packet contains quick check bytes, the actual plaintext and modification detection code +``` + +Lastly, the whole prepared plaintext is encrypted symmetrically. + +(seipd-v2)= +### v2 SEIPD, based on AEAD + +The [version 2 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#version-two-seipd) mechanism was introduced in OpenPGP version 6. Consequently, it can only be used for encryption when all recipients explicitly announce support for it using a *Feature* signature subpacket. +It provides integrity protection of the ciphertext using *AEAD* (authenticated encryption with additional data). +v2 SEIPD can only be combined with either [version 6 PKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v6-pkesk) and/or [version 6 SKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v6-skesk) packets. + +In version 2 SEIPD, the *session key* is transformed into a *message key*, based on a per-message salt value stored separately in the v2 SEIPD packet. The message key is then used in an AEAD scheme to encrypt the message payload. + +```{note} +The session key can use a different symmetric algorithm than the message key. +``` + +```{figure} plain_svg/SEIPDv2-PKESK.svg +:name: fig-encryption-seipdv2-pkesk +:alt: TODO + +With SEIPDv2, the message key is derived from the session key in an extra step. +``` + +This additional step introduces key-separation into the protocol, which protects against certain attacks, such as an [OpenPGP SEIP downgrade attack](https://www.metzdowd.com/pipermail/cryptography/2015-October/026685.html). diff --git a/book/source/examples/ascii_armored_encrypted_message.asc b/book/source/examples/ascii_armored_encrypted_message.asc new file mode 100644 index 0000000..68bfa3f --- /dev/null +++ b/book/source/examples/ascii_armored_encrypted_message.asc @@ -0,0 +1,9 @@ +-----BEGIN PGP MESSAGE----- + +wV0GIQbApYOEpDjloU9zcSQmpNRduu70o55rMLCdVRP5eKzKlBkxYaQzuusD78oj +AdiGwQ8MI8sSAXAV4AEMKIcbINqhIBgSm5EV9h+Yl/XV3fEZ1JOaBnrtso2ZAS7S +cgIHAQaWc/Ip4Thq0EZDZwlpRUk/TUL+TWEpsGdQs8ifDyFAk7t3+3XvvLr5dUg3 ++Ot+sESkCSjhrZk50HIjwjBVZ6Y159yfaOqttMT6cXqWaxIishPaJ+OR1q2bZS1N +2jFbaROOcbASK6AVzqCWneqkIA== +=WFpq +-----END PGP MESSAGE----- diff --git a/book/source/glossary.md b/book/source/glossary.md new file mode 100644 index 0000000..76d7fed --- /dev/null +++ b/book/source/glossary.md @@ -0,0 +1,691 @@ + + +# Glossary + +```{glossary} +:sorted: + +AEAD + See {term}`Authenticated Encryption With Associated Data`. + +AEAD Algorithm + See {term}`Authenticated Encryption With Associated Data`. + +Algorithm Preferences + The preferences for {term}`hash algorithms`, {term}`compression algorithms`, {term}`symmetric algorithms` and {term}`AEAD algorithms` are set using {term}`direct key signatures` or {term}`primary User ID` {term}`binding signatures`. + + See [](recipe-algorithm-preferences). + +Asymmetric Cryptography + Asymmetric cryptography is used in OpenPGP. For a more detailed discussion see [](public-key-cryptography). + +Authenticated Encryption With Associated Data + Short AEAD, refers to an encryption scheme that ensures confidentiality of a message. Additionally, additional data, which is not confidential, may be associated with the message. + + See Wikipedia on [Authenticated Encryption](https://en.wikipedia.org/wiki/Authenticated_encryption). + +Authentication + The process of {term}`validiting` an {term}`identity claim`. + The term "authentication" here is semantically different from the one used in {term}`Authentication Key Flag`. + +Authentication Key Flag + A {term}`Key Flag`, which indicates that a {term}`Component Key` can be used to confirm control over {term}`private key material` against a remote system. The term "authentication" here is semantically different from {term}`Authentication`. See [](key-flags). + +Authentication Tag + See {term}`Message Authentication Code`. + +Authenticity + See {term}`Authentication`. + +Back Signature + See {term}`Primary Key Binding Signature`. + +Binary Signature + A {term}`Data Signature` with the {term}`Signature Type ID` `0x00`, which is used for binary data. + +Binding + The process of creating a {term}`Binding Signature` for a {term}`Component`, or the resulting {term}`Binding Signature`. + + See {ref}`binding-signatures` for more. + +Binding Signature + A {term}`self-signature` on a {term}`component` which associates that {term}`component` to the issuing {term}`component key` in a {term}`certificate`. + + See {ref}`binding-signatures` for more. + +CA + See {term}`Certification Authority`. + +Capability + The operations an {term}`OpenPGP Component Key` can perform. See [](key-flags). + +Certificate + See {term}`OpenPGP Certificate` + +Certificate Authority + See {term}`Certification Authority` + +Certificate Holder + A person or other entity, that holds an {term}`Transferable Secret Key` and thus is able to modify the accompanying {term}`OpenPGP Certificate`. + +Certification + A certification, in OpenPGP, is a signature that makes a statement about an {term}`identity` in a {term}`certificate`, or an entire {term}`certificate`. + + Most commonly, the term is applied to "[third-party certifications](third-party-certifications)," in which an external actor indicates that they have {term}`validated` the link between an {term}`identity` and a {term}`certificate`. However, the term is also used for [self-signatures that bind identity components](bind-identity) to a {term}`certificate`. + +Certification Authority + Also known as [Certificate authority](https://en.wikipedia.org/wiki/Certificate_authority), this is an entity that handles digital certificates, especially by signing or issuing them. + +Certification Key Flag + A {term}`Key Flag`, indicating that a {term}`Component Key` can be used for issuing third-party {term}`certifications`. See [](key-flags). + +Certification Revocation Signature Packet + An {term}`OpenPGP Signature Packet` to {term}`revoke` an earlier {term}`self-certification` of a {term}`User ID`. + + [RFC 5.2.1.13](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-certification-revocation-si) + +Certification Signature + See {term}`Certification`. + +Certifying Self-signature + An {term}`OpenPGP Signature Packet` by the {term}`Certificate Holder` on an {term}`Identity Component` of their own {term}`Certificate`. + +Certifying Signature + See {term}`Certification`. + +Cipher Type Byte + This historical term was defined in [RFC 1991](https://datatracker.ietf.org/doc/html/rfc1991#section-4.1) and was subsequently superseded by {term}`Packet Tag` in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440#section-4.2), which is in turn superseded by {term}`Packet Type ID` in the new [RFC](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers). + +Cleartext Signature + A {term}`Data Signature` which exists in a combined text format, encapsulating the (readable) text input it was created for. See [](cleartext-signature). + +Cleartext Signature Framework + A framework for creating {term}`cleartext signatures`. + See [RFC 7](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#cleartext-signature). + +Component + An element in an {term}`OpenPGP Certificate`, that represents a {term}`component key` or {term}`identity component`. + +Component Key + See {term}`OpenPGP Component Key`. + +Compression + See {term}`Data Compression`. + +Creation Time + The point in time at which e.g. an {term}`OpenPGP Certificate`, or one of its {term}`component` is created. + +Creator + See {term}`Issuer`. + +Criticality Flag + A flag on {term}`Subpacket`s, that defines their criticality, which is used for validation. See [](criticality-of-subpackets). + +Cryptographic Key + A {term}`symmetric` or {term}`asymmetric` cryptographic key is used for signing and encryption operations. See [](cryptography). + +Cryptographic Signature + A raw cryptographic signature is a sequence of bytes created by a {term}`Cryptographic Key`. + +CTB + See {term}`Cipher Type Byte`. + +Data Compression + The process of encoding information using fewer bits than the original representation. + In OpenPGP data compression is used to reduce the size required for encrypted messages. + + See Wikipedia on [Data Compression](https://en.wikipedia.org/wiki/Data_compression). + +Data Signature + {term}`Cryptographic signature` over binary documents or canonical text documents. See [](/signing_data). + +Data Signature Packet + An {term}`OpenPGP Signature Packet` which describes a {term}`Data Signature`. See [](/signing_data). + +Delegation + OpenPGP users can [delegate authentication decisions](delegation) to third parties, and thus rely on {term}`certifications` they issue. The remote party is then called a "{term}`trusted introducer`". + + This kind of delegation involves {term}`certifications` that include the {term}`trust signature` subpacket. + +Detached Signature + A {term}`Data Signature` which exists as a separate file to the file it was created for. See [](forms-of-data-signatures). + +Direct Key Signature + A {term}`Signature` that sets preferences and advertises {term}`features` applicable to an entire {term}`Certificate`. See [](direct-key-signature). + +Embedded Signature Subpacket + An {term}`OpenPGP Signature Subpacket` which contains a complete {term}`OpenPGP Signature Packet`. + + See [RFC 5.2.3.34](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-embedded-signature) + +Encryption Key Flag + A {term}`Key Flag`, indicating that a {term}`Component Key` can be used for encrypting data. See [](key-flags). + +Expiration + A mechanism by which a {term}`Component` is invalidated due to the {term}`Expiration Time` of its {term}`binding signature` being older than the {term}`Reference Time` by which it is validated. + +Expiration Time + The time of expiry of an {term}`OpenPGP Signature Packet`. + +Features Subpacket + A {term}`OpenPGP Signature Subpacket`, which denotes advanced OpenPGP features an {term}`implementation` supports. + + For an in-depth view on these {term}`subpackets` see [](zoom-dks). + + See [RFC 5.2.3.32](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-features) + +Fingerprint + See {term}`OpenPGP Fingerprint`. + +Hard Revocation + A {term}`Revocation Signature Packet` for a {term}`Certification` or a {term}`Component Key`, which either includes a {term}`Reason For Revocation Subpacket` with a {term}`Revocation Code`, that signifies the target being compromised (e.g., `0` or `2`), or has no {term}`Reason For Revocation Subpacket` at all. + + See [](hard-vs-soft-revocations). + + See [RFC 5.2.3.31](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-reason-for-revocation). + +Hash Algorithm + See {term}`Hash Function`. + +Hash Digest + Output of a cryptographic hash function for a string of data of any length. See [](cryptographic-hash). + +Hash Function + A function used to map data of arbitrary size to fixed-size values (see {term}`Hash Digest`). + +Hashed Area + An area in an {term}`OpenPGP Signature Packet` containing {term}`OpenPGP Signature Subpacket`s, that is covered by the {term}`Hash Digest` a {term}`Cryptographic Signature` is created for. See [](subpacket-areas). + +Hashed Subpacket + An {term}`OpenPGP Signature Subpacket` residing in the {term}`Hashed Area` of an {term}`OpenPGP Signature Packet`. + +Hybrid Cryptosystem + A cryptographic system that employs both {term}`Asymmetric Cryptography` and {term}`Symmetric Cryptography`. See [](hybrid-cryptosystems). + +Identity + An identity of a {term}`Certificate Holder`. It is represented by an {term}`Identity Component`, which may be certified using {term}`third-party identity certifications`, or by a {term}`Notation`. + +Identity Certification + An {term}`OpenPGP Signature Packet` on an {term}`Identity Component` which {term}`certifies` its {term}`authenticity`. + +Identity Claim + A {term}`Certificate Holder` may use {term}`Identity Components` or {term}`Notations` to state a claim about their {term}`Identity`. + +Identity Component + Part of an {term}`OpenPGP Certificate`, that is used to associate data about the {term}`Certificate Holder` with it. See [](identity-components) for further details. + +Identity Verification + A process by which the {term}`Identity Claim` of a {term}`Certificate Holder` is verified. See also {term}`Signature Verification`. + +Initial Introducer + An {term}`OpenPGP Certificate` explicitly {term}`delegated` to from a {term}`Trust Anchor`. + +Inline Signature + A {term}`Data Signature` which exists encapsulated alongside the data it was created for in an OpenPGP container. See [](forms-of-data-signatures). + +Issuer + An entity, that created an {term}`OpenPGP Signature Packet` using an {term}`Transferable Secret Key`. + +Issuer Fingerprint Subpacket + A {term}`Subpacket` specifying the {term}`Fingerprint` of an {term}`Issuer Key`. + + See [RFC 5.2.3.35](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-issuer-fingerprint) + +Issuer Key + The {term}`OpenPGP Component Key` of an {term}`Issuer`, used to create an {term}`OpenPGP Signature Packet`. + +Key + In OpenPGP, and cryptography more generally, the term "key" holds different meanings. + + First, it can apply to different [cryptographic primitives](/cryptography): + + - asymmetric public key + - asymmetric private key + - {term}`Symmetric Secret Key` + + Additionally, in OpenPGP, asymmetric cryptographic keys are used on [three different layers](layers-of-keys-in-openpgp) of abstraction: + + - cryptographic key + - OpenPGP component key + - {term}`OpenPGP key` (which in turn refers to either an {term}`OpenPGP Certificate` or a {term}`Transferable Secret Key` + +Key Expiration Time Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the {term}`Expiration Time` for an {term}`OpenPGP Signature Packet` on a {term}`key`. + + See [RFC 5.2.3.13](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-expiration-time) + +Key Flag + A preference encoded in an {term}`OpenPGP Signature Subpacket`, that defines the {term}`Capability` a {term}`OpenPGP Component Key` has. See [](signature-subpackets). + +Key Holder + See {term}`Certificate Holder`. + +Key ID + The high-order (leftmost) 64 bits of an {term}`OpenPGP Fingerprint`. + Historically, this term refers to the low-order (rightmost) 64 bits of an {term}`OpenPGP Fingerprint`. + +Key Material + May refer to {term}`Public Key Material` or {term}`Private Key Material`. + +Key Owner + See {term}`Certificate Holder`. + +Key Revocation Signature Packet + A {term}`Revocation Self-signature` for an entire {term}`OpenPGP Certificate`. + +Key Server + A piece of software available over the network, which provides access to {term}`OpenPGP Certificates` e.g., by searching for an {term}`OpenPGP Fingerprint` or {term}`User ID`, via the `HKP` and/ or `HKPS` protocols. + Several implementations such as [hagrid](https://gitlab.com/keys.openpgp.org/hagrid/), or [hockeypuck](https://github.com/hockeypuck/hockeypuck) exist. + +Life-cycle Management + In OpenPGP several actions are necessary for the prolonged use of an {term}`OpenPGP Certificate` or adapting its {term}`components` to the requirements of the {term}`Certificate Holder`. + These are for example changes to {term}`binding signatures` (adding or {term}`revocation` of {term}`component keys` or {term}`direct key signature`), modification of {term}`expiration time` or other {term}`metadata` for {term}`components`. + See [](self-signatures). + +Literal Data Packet + A {term}`packet` in a {term}`Data Signature` which contains data, that has been signed using a {term}`cryptographic signature`. See [RFC 5.9](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#lit) for more details. + +MAC + See {term}`Message Authentication Code`. + +Master Key + See {term}`OpenPGP Primary Key`. + +Message Authentication Code + A piece of information used for integrity and {term}`authenticity` verification of a message. See [](message-authentication-code). + +Meta-Introducer + An {term}`OpenPGP Certificate` with a {term}`Trust Depth` greater than one. + +Metadata + Data related to preferences of an {term}`OpenPGP Certificate` or its {term}`Certificate Holder`, that can be found in {term}`signature` {term}`packets`. See [](metadata-in-certificates). + +Notation + A mechanism for a {term}`Certificate Holder` to provide user-defined data using a {term}`Notation Signature Subpacket`. + +Notation Signature Subpacket + An {term}`OpenPGP Signature Subpacket` which is used to add user-defined data to a {term}`Certificate`. See [](notation-signature-subpackets). + +Notation Tag + Part of a {term}`Notation` name. + +One-pass Signature Packet + One or more {term}`packets` before the actual data in a {term}`Data Signature` which contain information to allow a receiving {term}`implementation` to create {term}`hashes` required for signature verification. See [RFC 5.4](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#one-pass-sig) for more details. + +OpenPGP Certificate + An OpenPGP certificate contains public key material, identity claims and third party certifications (but no private key material) + +OpenPGP Component Key + An {term}`OpenPGP Primary Key` or {term}`OpenPGP Subkey`. For an in-depth discussion see [](component-keys). + +OpenPGP Fingerprint + An OpenPGP Fingerprint is a shorthand representation of an {term}`OpenPGP Component Key`. Fingerprints effectively act as unique identifiers. See [](fingerprint). + + The Fingerprint of the {term}`primary component key` is used as an identifier for the full {term}`OpenPGP Certificate`. + +OpenPGP Implementation + A piece of software implementing the OpenPGP protocol (to some extend). + +OpenPGP Key + Used either for an {term}`OpenPGP Certificate` (containing public key material and metadata), or for an {term}`OpenPGP Private Key`. See [](/certificates) for an in-depth discussion. + +OpenPGP Message + A data structure, which contains OpenPGP components such as {term}`OpenPGP Certificate` or {term}`OpenPGP Signature Packet` and plaintext or encrypted data. + +OpenPGP Public Key + See {term}`OpenPGP Certificate`. + +OpenPGP Private Key + See {term}`Transferable Secret Key`. + +OpenPGP Primary Key + An {term}`OpenPGP Component Key` that is used in the primary key role of an {term}`OpenPGP Certificate`. For a more detailed discussion, see [](primary-key). + +OpenPGP Signature + See {term}`OpenPGP Signature Packet`. + +OpenPGP Signature Packet + A {term}`packet` that contains a raw {term}`cryptographic signature`, a {term}`Signature Type ID` and additional {term}`metadata`. See [](/signatures). Basic concepts are introduced in [](/signatures) and more detailed use-cases are explained in [](/signing_data) and [](/signing_components). + +OpenPGP Signature Subpacket + A data structure in a {term}`Signature Packet`, that describes {term}`metadata` and preferences. See [](signature-subpackets). + +OpenPGP Signature Subpacket Type + An {term}`OpenPGP Signature Subpacket` type. + +OpenPGP Signature Type + The type of an {term}`OpenPGP Signature Packet` is defined by its {term}`Signature Type ID`. See [](signature-types). + +OpenPGP Signing Subkey + An {term}`OpenPGP Subkey` with the {term}`Signing Key Flag`. + +OpenPGP Subkey + An {term}`OpenPGP Component Key` that is used in the subkey role, in an {term}`OpenPGP Certificate`. For a more detailed discussion, see [](subkeys). + +Owner + See {term}`Certificate Holder`. + +Packet + An element in an {term}`OpenPGP Certificate`, which represents {term}`components` or {term}`signatures`. + +Packet Header + A section of variable length at the beginning of a {term}`Packet`, which encodes for example the {term}`Packet Type ID`. See the relevant [section in the RFC](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers), which explains this section in more detail. + +Packet Tag + This historical term was defined in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440#section-4.2) and is superseded by {term}`Packet Type ID` in the new [RFC](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers). + +Packet Type ID + A numerical value encoded in the first octet of a {term}`Packet Header`, defining a {term}`Packet`'s type. + +Positive Certification + An {term}`OpenPGP Signature Type` with the {term}`Signature Type ID` `0x13`, which is used in {term}`binding signatures` for {term}`User IDs`. This {term}`OpenPGP Signature Type` implies that the {term}`issuer` has done substantial {term}`verification` of the {term}`Identity Claim`. + + See [](bind-identity). + +Preferred Compression Algorithms Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the preferred {term}`compression algorithms` for an {term}`OpenPGP Signature Packet`. This defines which {term}`algorithms` the {term}`key holder` prefers to use. + + See [RFC 5.2.3.17](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-preferred-compression-algor). + +Preferred Hash Algorithms Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the preferred {term}`hash algorithm` for an {term}`OpenPGP Signature Packet`. This defines which algorithms the {term}`key holder` prefers to receive. + + See [RFC 5.2.3.16](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-preferred-hash-algorithms). + +Preferred Symmetric Ciphers for v1 SEIPD Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the preferred version 1 {term}`SEIPD` algorithms for an {term}`OpenPGP Signature Packet`. This defines which algorithms the {term}`key holder` prefers to receive and implicitly signifies the supported algorithms of the {term}`key holder`'s {term}`implementation`. + + See [RFC 5.2.3.14](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-preferred-symmetric-ciphers). + +Preferred AEAD Ciphersuites Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the preferred version 2 {term}`SEIPD` algorithms for an {term}`OpenPGP Signature Packet`. This defines which algorithms the {term}`key holder` prefers to receive and implicitly signifies the supported algorithms of the {term}`key holder`'s {term}`implementation`. + + See [RFC 5.2.3.15](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-preferred-aead-ciphersuites) + + +Primary Component Key + See {term}`OpenPGP Primary Key`. + +Primary Introducer + See {term}`Initial Introducer`. + +Primary Key + See {term}`OpenPGP Primary Key`. + +Primary Key Binding Signature + A {term}`Binding Signature`, which is created by a {term}`OpenPGP Signing Subkey` on the {term}`OpenPGP Primary Key` of an {term}`OpenPGP Certificate` and stored in an {term}`Embedded Signature Subpacket` in the {term}`Binding Signature` for the {term}`OpenPGP Signing Subkey`. + + This special case is explained in more detail in [](bind-signing-subkey). + +Primary User ID + A {term}`User ID` which carries the default preferences for {term}`identity components` without preferences. + + See [](primary-user-id). + +Primary User ID Subpacket + An {term}`OpenPGP Signature Subpacket` used in {term}`User ID self-signatures` which allows to signify whether the {term}`User ID` in question is considered a {term}`Primary User ID`. + + See [RFC 5.2.3.27](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#primary-user-id-subpacket) + +Primary User ID Binding Signature + A {term}`Binding Signature`, which is created by an {term}`OpenPGP Primary Key` to bind a {term}`User ID` to its {term}`OpenPGP Certificate` and marking it as the {term}`Primary User ID`. + + This {term}`Binding Signature` may carry {term}`metadata` specific to the {term}`User ID` at hand as well as some applicable to the entire {term}`OpenPGP Certificate`. + + See [](primary-user-id-binding). + +Private Key + See {term}`Transferable Secret Key`. + +Private Key Material + A raw cryptographic private key. + +Public Key + See {term}`OpenPGP Public Key`. + +Public Key Algorithm + An {term}`asymmetric cryptographic` algorithm. See [](public-key-cryptography). + +Public Key Cryptography + See {term}`Asymmetric Cryptography`. + +Public Key Material + See {term}`OpenPGP Certificate`. + +Reason For Revocation Subpacket + An {term}`OpenPGP Signature Subpacket`, which is used in {term}`Certification Revocation Signature Packet` and {term}`key revocation signature packets` to describe a reason for the {term}`revocation`. + + See [RFC 5.2.3.31](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-reason-for-revocation) + +Reference Time + A point in time at which an {term}`OpenPGP Certificate` is evaluated. + +Regular Expression Subpacket + An {term}`OpenPGP Signature Subpacket` which allows for limiting {term}`delegations` to {term}`identities` matching a regular expression. + +Revocation + Mechanism to invalidate a {term}`component` or an entire {term}`OpenPGP Certificate` using a {term}`Revocation Self-signature`. See [](revocations). + +Revocation Certificate + A {term}`Revocation Self-signature` for an {term}`OpenPGP Primary Key` distributed alongside the plain {term}`OpenPGP Primary Key`. + + See [RFC 10.1.2](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-openpgp-v6-revocation-certi) + + Note that in [OpenPGP v4 this term is typically used](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-10.1.3-6) for a bare {term}`Revocation Self-signature` {term}`packet`. + +Revocation Code + A number in a {term}`Reason For Revocation Subpacket` which represents the reason for a {term}`Revocation`. + +Revocation Self-signature + A class of {term}`self-signatures` to {term}`revoke` {term}`primary keys`, {term}`User IDs` or {term}`User Attributes` and invalidate {term}`subkey binding signatures`. + + See [](self-revocations). + +Revocation Signature + See {term}`Revocation Signature Packet`. + +Revocation Signature Packet + An {term}`OpenPGP Signature Packet` used for the {term}`revocation` of a {term}`certification` or {term}`binding`. + + Revocation signatures are often {term}`self-signatures`, more specifically {term}`revocation self-signatures`. + However, *{term}`certification revocations`* can be both {term}`self-signatures` or {term}`third-party signatures`. + Additionally, with the deprecated *Revocation Key* mechanism, {term}`third-party` *Key-* and *Subkey revocations* also exist. + +RFC + This document, unless noted otherwise, refers to the [OpenPGP version 6 specification](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/) when referring to *RFC*. + +SEIPD + See {term}`Symmetrically Encrypted Integrity Protected Data`. + +Self-certification + A {term}`certification` on a {term}`component` of an {term}`OpenPGP Certificate` issued by a {term}`component key` of the same {term}`OpenPGP certificate`. + +Secret Key Material + See {term}`Private Key Material`. + +Self-signature + An {term}`OpenPGP Signature Packet` by the {term}`Certificate Holder` on a {term}`Component` of their own {term}`Certificate`. + +Session Key + A unique shared secret used in encryption in a {term}`Hybrid Cryptosystem`. See [](encryption) and [](decryption). + +Soft Revocation + A {term}`Revocation Signature Packet` for a {term}`Certification` or a {term}`Component Key`, which includes a {term}`Reason For Revocation Subpacket` with a {term}`Revocation Code`, that does not signify the target being compromised (e.g., `0` or `2`). + + See [](hard-vs-soft-revocations). + + See [RFC 5.2.3.31](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-reason-for-revocation). + +Signature + See {term}`OpenPGP Signature Packet`. + +Signature Creation Time Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the {term}`Creation Time` for an {term}`OpenPGP Signature Packet`. + + See [RFC 5.2.3.11](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-creation-time) + +Signature Expiration Time Subpacket + An {term}`OpenPGP Signature Subpacket Type` which defines the {term}`Expiration Time` for an {term}`OpenPGP Signature Packet`. + + See [RFC 5.2.3.18](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-expiration-time) + +Signature On Component + {term}`Cryptographic signature` associated with {term}`Component Keys` or {term}`Identity Components`. See [](/signing_components). + +Signature Over Data + See {term}`Data Signature`. + +Signature Packet + See {term}`OpenPGP Signature Packet`. + +Signature Subpacket + See {term}`OpenPGP Signature Subpacket`. + +Signature Subpacket Type + See {term}`OpenPGP Signature Subpacket Type`. + +Signature Type + See {term}`OpenPGP Signature Type`. + +Signature Type ID + A numerical identifier for a {term}`Signature Type`. + +Signature Verification + In cryptography the mechanism of verification relates to a process in which a claim (i.e., a {term}`signature`) is tested (i.e., using the relevant {term}`components` of a {term}`certificate`). + +Signer + A {term}`Certificate Holder`, that is able to create {term}`self-signatures` and {term}`third-party signatures`. + +Signing-capable + See {term}`Signing Key Flag`. + +Signing Key Flag + A {term}`Key Flag`, indicating that a {term}`Component Key` can be used for signing data. See [](key-flags). + +Signing Subkey + See {term}`OpenPGP Signing Subkey`. + +Strong Authentication + "Strong Authentication" in this text refers to having ascertained that a {term}`certificate` and an {term}`identity claim` on it are legitimately linked. That is, that the person who controls the {term}`certificate` is correctly represented by the {term}`identity component`. + + Strong authentication in OpenPGP is typically encoded with a {term}`certification signature`. + + Ascertaining strong authentication requires an out-of-band check: Either via a manual {term}`verification` process, or an automated system that can {term}`certify` that a user has identified to the system that issues the {term}`identity` in question (e.g. an email provider can {term}`certify` email-based {term}`identities` that it issues to the user). + + Also see {term}`Authentication`. + +Subkey + See {term}`OpenPGP Subkey`. + +Subkey Binding Signature + A {term}`Self-signature` to associate an {term}`OpenPGP Subkey` with an {term}`OpenPGP Primary Key`. See [](bind-subkey). + +Subkey Revocation Signature Packet + A {term}`Self-signature` to {term}`revoke` an {term}`OpenPGP Subkey` in an {term}`OpenPGP Certificate`. + + See [RFC 5.2.1.12](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-subkey-revocation-signature) + +Subpacket + See {term}`OpenPGP Signature Subpacket`. + +Subpacket Type + See {term}`OpenPGP Signature Subpacket Type`. + +Symmetric Cryptography + Symmetric cryptography is used in OpenPGP. For a more detailed discussion see [](symmetric-key-cryptography). + +Symmetrically Encrypted Integrity Protected Data + Short *SEIPD*, this refers to {term}`Symmetric Cryptography` based encrypted data, which is used in a Symmetrically Encrypted Integrity Protected Data Packet. + + See [RFC 5.13](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetrically-encrypted-int). + +Symmetric Secret Key + The {term}`Private Key Material` used in {term}`Symmetric Cryptography`. + +Text Signature + A {term}`signature packet` with the {term}`Signature Type ID` `0x01`, which is used for textual data. + +Third-party Identity Certification + {term}`Certification` by third-parties to confirm ownership of an {term}`OpenPGP Certificate` by a {term}`Certificate Holder`. See [](third-party-identity-certifications). + +Third-party Signature + A {term}`Signature` by a third-party on a {term}`Component` of a {term}`Certificate`. + +Transferable Secret Key + A Transferable Secret Key (TSK) is the combination of an {term}`OpenPGP Certificate` and the associated {term}`private key material`. Also often referred to as an "OpenPGP private key". It is discussed in detail in [](/private_keys). + +Trust Amount + A numerical value between `0` and `255`, stored in {term}`trust signatures` used for indicating the degree of reliance on the {term}`delegation`. + Values less than `120` indicate partial trust, values equal to or greater than `120` indicate complete trust. + + See [](trust-amount). + See [RFC 5.2.3.21](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-trust-signature) + +Trust Anchor + An entity in a {term}`Trust Model` for which trust is assumed and not derived. + +Trust Depth + This numerical value is part of a {term}`Trust Signature` and describes the extent of trustworthiness of a {term}`Certification`, that the {term}`signer` assigns to it. + + See [](trust-level). + +Trust Level + See {term}`Trust Depth`. + +Trust Model + A model by which trust between {term}`identities` associated with different {term}`OpenPGP Certificates` is created. See [](third-party-identity-certifications). + +Trust Root + See {term}`Trust Anchor`. + +Trust Signature + The *trust signature* {term}`subpacket` on a {term}`certifying signature` is used for {term}`delegation` of {term}`authentication` decisions. With this feature, an OpenPGP user can designate a {term}`certificate` as a "{term}`trusted introducer`" and opt to rely on {term}`certifications` they issue. + + See [RFC 5.2.3.21](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-trust-signature) + +Trusted introducer + OpenPGP users can choose to rely on {term}`certifications` issued by a third party. The remote party of such a {term}`delegation` is called a "trusted introducer". + + See {ref}`delegation` for more details. + +TSK + See {term}`Transferable Secret Key`. + +tsig + See {term}`Trust signature` + +Type ID + See {term}`Signature Type ID`. + +Unhashed Area + An area in a {term}`Signature Packet` containing {term}`Signature Subpacket`s, that is *not* covered by the {term}`Hash Digest` a {term}`Cryptographic Signature` is created for. See [](subpacket-areas). + +Unhashed Subpacket + A {term}`Signature Subpacket` residing in the {term}`Unhashed Area` of a {term}`Signature Packet`. + +User Attribute + An {term}`Identity Component`, which may hold a single JPEG image. See [](user-attributes). + +User ID + An {term}`Identity Component`, which describes an {term}`Identity` of a {term}`Certificate Holder`. See [](user-ids). + +User ID Binding Signature + A {term}`Binding Signature`, which is created by an {term}`OpenPGP Primary Key` to bind a {term}`User ID` to an {term}`OpenPGP Certificate`. + +Validation + A mechanism by which the [operational needs of a use-case are met](https://en.wikipedia.org/wiki/Verification_and_validation#Validation). + In OpenPGP terminology this may refer to processes such as ensuring, that an {term}`OpenPGP Signature Packet` has been created after a {term}`Transferable Secret Key`'s {term}`Creation Time`, but before its {term}`Expiration Time`. + +Validity + See {term}`Validation`. + +Verification + A mechanism by which the [compliance with design specifications are met](https://en.wikipedia.org/wiki/Verification_and_validation#Verification). + In OpenPGP terminology this may refer to e.g. {term}`Signature Verification` or {term}`Identity Verification`. + +Web Of Trust + A {term}`trust model` which is based on a network of {term}`certifications` and {term}`delegations`, that can be used to discern the reliability of {term}`certificates` and their associated {term}`identities`. See [](wot). +``` diff --git a/book/source/img/README b/book/source/img/README new file mode 100644 index 0000000..748fa06 --- /dev/null +++ b/book/source/img/README @@ -0,0 +1 @@ +Generated image data, based on source material in book/assets/ diff --git a/book/source/img/drawio/attribute-shadowing.png b/book/source/img/drawio/attribute-shadowing.png new file mode 100644 index 0000000..f09062d Binary files /dev/null and b/book/source/img/drawio/attribute-shadowing.png differ diff --git a/book/source/img/drawio/cert-validity-key-expiration.png b/book/source/img/drawio/cert-validity-key-expiration.png new file mode 100644 index 0000000..06a202d Binary files /dev/null and b/book/source/img/drawio/cert-validity-key-expiration.png differ diff --git a/book/source/img/drawio/cert-validity-simple.png b/book/source/img/drawio/cert-validity-simple.png new file mode 100644 index 0000000..36ab24a Binary files /dev/null and b/book/source/img/drawio/cert-validity-simple.png differ diff --git a/book/source/img/drawio/cert-validity-subkey.png b/book/source/img/drawio/cert-validity-subkey.png new file mode 100644 index 0000000..6c0571a Binary files /dev/null and b/book/source/img/drawio/cert-validity-subkey.png differ diff --git a/book/source/img/drawio/dk-attributes-and-shadowing.png b/book/source/img/drawio/dk-attributes-and-shadowing.png new file mode 100644 index 0000000..73e8292 Binary files /dev/null and b/book/source/img/drawio/dk-attributes-and-shadowing.png differ diff --git a/book/source/img/drawio/narrow-interpretation.png b/book/source/img/drawio/narrow-interpretation.png new file mode 100644 index 0000000..0eb3520 Binary files /dev/null and b/book/source/img/drawio/narrow-interpretation.png differ diff --git a/book/source/img/mermaid/09-sigtree.png b/book/source/img/mermaid/09-sigtree.png new file mode 100644 index 0000000..dc35f65 Binary files /dev/null and b/book/source/img/mermaid/09-sigtree.png differ diff --git a/book/source/img/mermaid/sig-types.png b/book/source/img/mermaid/sig-types.png new file mode 100644 index 0000000..df7d388 Binary files /dev/null and b/book/source/img/mermaid/sig-types.png differ diff --git a/book/source/index.md b/book/source/index.md new file mode 100644 index 0000000..a314ec7 --- /dev/null +++ b/book/source/index.md @@ -0,0 +1,51 @@ + + +# OpenPGP for application developers + +**{sub-ref}`today`** + +```{toctree} +:numbered: +:maxdepth: 2 +:glob: + +about.md +openpgp.md +cryptography.md +certificates.md +private_keys.md +signatures.md +signing_data.md +signing_components.md +verification.md +encryption.md +decryption.md +compression.md +armor.md +pitfalls.md +policy.md +versions.md +migration.md + +adv/certificates.md +adv/private_keys.md +adv/signatures.md +adv/signing_data.md +adv/signing_components.md +adv/verification.md +adv/encryption.md +adv/decryption.md + +zoom/certificates.md +zoom/private_keys.md +zoom/signatures.md +zoom/encryption.md + +glossary.md +acknowledgements.md + +artifacts.md +``` diff --git a/book/source/migration.md b/book/source/migration.md new file mode 100644 index 0000000..5d17ce7 --- /dev/null +++ b/book/source/migration.md @@ -0,0 +1,114 @@ + + +# Migration from OpenPGP v4 to v6 + +The OpenPGP protocol has developed over time, and will continue to do so, adapting to new challenges and expectations. + +Some of these changes might be subtle, like the addition of a new hash algorithm, while others are more invasive, like a new OpenPGP key format. + +This makes it necessary to migrate both implementations and existing user keys and certificates. + +In this chapter, we want to explore possible steps to migrate from OpenPGP v4 as defined by RFC4880 to v6 (crypto-refresh). + +## Adoption of new features + +The new standard introduced a number of new features, which improve security aspects of the protocol. +Some of these features can only be used with new OpenPGP version 6 keys, and require users to migrate to fresh keys. + +Other features can be used with existing OpenPGP version 4 keys, as soon as implementations support the features, and users' certificates reflect that the features are supported by the user's software. + +### SEIPD v2 + +A perfect example for a newly introduced feature that can be applied to existing v4 keys are the new SEIPD v2 packets. + +Existing OpenPGP v4 keys can simply announce support for SEIPD v2 via a *Feature* subpacket in their certificate. Publishing such an updated *Feature* set via their OpenPGP certificate signals that the user's OpenPGP software is capable of handling SEIPD v2. + +Senders who can produce this new encryption mode can then opt to use it when encrypting to this recipient. + +(migration-s2k)= +### S2K usage mode AEAD + +Another good example is the S2K mechanism for secret-key encryption. + +This feature concerns local copies of OpenPGP private keys on each user's machine. There is, by definition, no interoperability concern around this feature: Passphrase-protection of the private key material is a local implementation detail on each user's machine. + +The RFC [states](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-avoiding-ciphertext-malleab) that: "Users are RECOMMENDED to migrate to AEAD." + +In the context of this chapter, this means that encrypted private keys should be upgraded by the user's OpenPGP software to use [S2K usage mode 253](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption-s2k-u) (AEAD) to encrypt the user's private key material. + +Note that S2K usage mode 253 (AEAD) can be applied to both version 6 and version 4 private keys, with sufficiently up-to-date OpenPGP software. This S2K usage mode is strongly recommended for private keys of all versions. + +#### S2K method Argon2 + +Independently, the RFC recommends the use of the Argon2 S2K method to hash passphrases, when it is available. This mechanism also concerns the local passphrase-protection of private key material. + +Use of Argon2 is only allowed in combination with AEAD. + +Users can and should migrate the protection of their private keys to Argon2 (combined with the AEAD usage mode). + +### OpenPGP v6 signatures + +Version 6 signatures can't be generated with OpenPGP v4 keys. Only OpenPGP v6 keys can issue v6 signatures. + +On the receiving/verifying side, v6 signatures can be checked by anyone whose OpenPGP software supports v6 certificates and v6 signature verification. This includes OpenPGP users who currently use a v4 key. + +### Software migration + +Over time, steadily more OpenPGP libraries and tools will add support for OpenPGP v6 features. This migration might take a while, while implementers catch up. + +The OpenPGP v6 standard gives guidance for library authors to extend an OpenPGP implementation to support version 6 in [Appendix B. Upgrade Guidance](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-upgrade-guidance-adapting-i). + +## Key migration + +Some OpenPGP v6 features are only available for use with keys in the v6 format. + +For example, only an [OpenPGP v6 key can issue a v6 signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-versions-in-signatur). + +On the other hand, an OpenPGP v6 key can *only* issue v6 signatures, so if you require compatibility with v4 verifiers, you shouldn't yet migrate to a v6 key/certificate. + +When migrating to a v6 key, generating a fresh v6 key is the recommended approach. + +It is not possible to adopt v4 subkeys into a v6 key, since every subkey to a v6 primary key must itself be a v6 subkey, see in [OpenPGP v6 certificate structure](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-10.1.1-5). + +### Converting v4 component keys into v6 component keys + +That is, taking the existing key material from a v4 component key and re-framing it as a v6 component key, for use with an OpenPGP version 6 certificate. + +```{admonition} TL;DR +:class: info + +don't. +``` + +#### Motivation to convert + +It might be tempting to consider migrating existing key material to the v6 format. Such a step should be considered very carefully though. + +Unfortunately, keys cannot simply be converted into the new format, and used seamlessly. For one thing, the Fingerprint of component keys changes for the same key material between version 4 and version 6 (and with it, the Key ID that is a shortened version of the Fingerprint). + +An OpenPGP v4 Fingerprint is calculated as the SHA-1 checksum of the normalized public key packet, which results in a 20 byte fingerprint (often represented as a 40 character hexadecimal string). The v4 Key ID consists of the *last* 64 bits of the fingerprint. + +On the other hand, a v6 fingerprint is calculated as the SHA-256 checksum of the normalized public key packet, so it comprises 32 bytes. The v6 Key ID consists of the *first* 64 bit of the fingerprint. + +As a consequence, component key identifiers in OpenPGP artifacts, such as issuer subpackets in signatures, or recipient Key IDs in PKESK packets issued by a v4 key do not match the component key identifiers of same key material converted to v6. + +Further, v6 keys can only issue v6 signatures, and v6 certificates can only be used to verify v6 signatures. Otherwise, a downgrade vector could exist, by which verifiers could be tricked into verifying specially crafted v4 signatures against OpenPGP v6 certificates. If a vulnerability arose in OpenPGP v4 at some point, which allows an attacker to craft valid v4 signatures, this could affect OpenPGP v6 certificates. + +#### Retaining decryption access to old messages + +Another motivation for converting old key material might be the desire to stay able to decrypt messages encrypted for the old key. +This won't be possible out of the box, as the Key ID in the respective PKESK packet no longer matches that of the converted key. So at the bare minimum, the user's implementation would need to be able to map Key IDs. This is not a feature prevalent in the ecosystem though. + +An alternative approach - that doesn't require special handling in the user's OpenPGP software - is to replace the PKESK headers of the messages. The session key for each message can be easily obtained by decrypting the message using the old key, so the session key can be re-encrypted for either the converted v6 key, or a freshly generated v6 key. This new PKESK packet can be added to, or replaced in, the message. + +#### Conclusion + +In conclusion, converting v4 key material to v6 to verify old signatures is not a strong argument. +Being able to read old messages using a converted key is also not really viable, since it is equally simple to just re-create the PKESK headers for a fresh v6 key. + +```{note} +Also see +``` diff --git a/book/source/openpgp.md b/book/source/openpgp.md new file mode 100644 index 0000000..c76b78e --- /dev/null +++ b/book/source/openpgp.md @@ -0,0 +1,112 @@ + + +# A high-level view + +## Why OpenPGP? + +OpenPGP is a widely recognized, IETF-standardized set of cryptographic operations. It is broadly used in securing communications, like encrypted messages and email, and ensuring the integrity of software packages in most Linux distributions. It enjoys a vast ecosystem of libraries, tools, and community support forums. Moreover, its robustness and versatility have made OpenPGP a security choice for other use cases in which encryption and integrity are important. These include file transfer applications, password managers, secure data storage, and signing source code in git repositories. + +There are other compelling reasons for why you might consider using OpenPGP in your project: + +1. **Decentralized trust model**: OpenPGP's decentralization defines mechanisms for {term}`authentication` that allow individuals and entities to create and manage their own cryptographic {term}`identities`. Unlike centralized {term}`trust models`, decentralized {term}`trust models` empower individuals and entities to manage their own {term}`identities`, fostering a community-driven web of trust instead of relying on a centralized authority, thus reducing single points of failure. + +2. **End-to-end encryption**: OpenPGP provides a robust framework for implementing end-to-end encryption. Content remains confidential, verifiable, {term}`authenticated`, and protected against unauthorized access, even when the communication channel itself might be otherwise compromised. Encryption is crucial in a myriad of scenarios, particularly when transmitting sensitive information such as financial data, personally identifiable information (PII), or proprietary business data. + +3. **Anonymity and pseudonymity**: In sensitive and volatile situations where identity protection is crucial, OpenPGP can be used to provide a level of anonymity or pseudonymity that helps protect user identities. For example, OpenPGP has been used alongside other privacy tools, such as [Tor](https://en.wikipedia.org/wiki/The_Tor_Project) and [VPN](https://en.wikipedia.org/wiki/Virtual_private_network)s, to provide secure and anonymous communication for whistleblowers, human rights lawyers, activists in repressive regimes, and journalists, reducing their risks for retaliation and state violence. + +4. **Interoperability**: OpenPGP is a well-structured and standardized protocol, widely adopted by various public and private entities but not tied to any particular vendor's technology. It supports all major operating systems, such as Windows, macOS, GNU/Linux, Android, and iOS. Because of standardization, wide adoption, cross-platform compatibility, and adaptability, OpenPGP's interoperability significantly contributes to reducing development time, costs, and technical hurdles. + +## A very brief history + +The OpenPGP standard has evolved over time, and remains under active development. + +(Also see [https://www.openpgp.org/about/history/](https://www.openpgp.org/about/history/)) + +### Pretty Good Privacy (PGP) + +The origins of OpenPGP can be traced back to *Pretty Good Privacy (PGP)*, a software program written by [Phil Zimmermann](https://en.wikipedia.org/wiki/Phil_Zimmermann) and first released in 1991. + +The original PGP software played a role in the political struggles sometimes referred to as the ["Crypto Wars"](https://en.wikipedia.org/wiki/Crypto_Wars) (also see ["Crypto: How the Code Rebels Beat the Government Saving Privacy in the Digital" (2002)](https://en.wikipedia.org/wiki/Crypto_(book)), which includes some of PGP's history). + +The original PGP software was never under a Free Software license, despite its source code being widely published by its author. [PGP's ownership has changed over the years](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#PGP_Corporation_and_Symantec), and [PGP's scope and suite of products have expanded](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#PGP_Corporation_encryption_applications). + +### Standardizing OpenPGP + +While PGP was first developed as commercial software, the owner at the time, PGP Inc., started a standardization effort with the IETF, first publishing [RFC 1991 "PGP Message Exchange Formats"](https://datatracker.ietf.org/doc/html/rfc1991) in August 1996. + +In July 1997, a process to produce an open standard under the then new name [OpenPGP](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP) was started, resulting in [RFC 2440 "OpenPGP Message Format"](https://datatracker.ietf.org/doc/html/rfc2440), published in November 1998. + +The name OpenPGP can be used freely by implementations, unlike the name PGP, which is a [registered trademark](https://uspto.report/TM/74685229). + +### GnuPG, an early Free Software implementation + +[First released 1997-12-20](https://gnupg.org/download/release_notes.html#sec-2-70) by Werner Koch, a German computer programmer, GNU Privacy Guard (GnuPG) is a free and open-source implementation of the OpenPGP standard. + +GnuPG was a major early implementation of OpenPGP. Over the years, the importance of GnuPG has grown significantly as it became a foundational tool for email security, software signing, and more. It played an important (and successful) role in the [release of NSA documents](https://theintercept.com/2014/10/28/smuggling-snowden-secrets/) by [Edward Snowden](https://en.wikipedia.org/wiki/Edward_Snowden). + +Because the GnuPG program binary is called "gpg," "GnuPG" and "gpg" are often used interchangeably. + +## The RFC 4880 era + +### OpenPGP version 4 + +In 2007, the IETF published [RFC 4880](https://datatracker.ietf.org/doc/html/rfc4880), which defines version 4 OpenPGP artifacts. As of late 2023, version 4 is the most commonly used version. + +An extension for Elliptic Curve Cryptography was defined in [RFC 6637](https://www.rfc-editor.org/rfc/rfc6637), specifying the use of three NIST prime field curves. + +Some implementations explored other non-standardized extensions. Notably, algorithms based on Curve 25519 were tentatively defined in the [rfc4880bis](https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#name-elliptic-curve-cryptography) document. These algorithms are widely used, even though rfc4880bis has never been finalized as a new version of the standard. + +(major-implementations)= +### Major implementations of OpenPGP + +Today, multiple implementations of OpenPGP play important roles: + +- The Mozilla Thunderbird email software uses [RNP](https://www.rnpgp.org/), a C++ implementation of OpenPGP. +- [GNU Privacy Guard (GnuPG)](https://gnupg.org/), a key implementation of the OpenPGP standard, is integral to numerous critical infrastructures, most prominently in ensuring package integrity verification for Linux distributions. +- Proton Mail, which provides email encryption services for a large number of users, uses and maintains [OpenPGP.js](https://openpgpjs.org/) as well as [GopenPGP](https://gopenpgp.org/), an OpenPGP wrapper library written in golang. +- The RPM Package Manager software includes an OpenPGP backend based on [Sequoia PGP](https://sequoia-pgp.org/), a modern OpenPGP implementation written in Rust. The Fedora Linux operating system [uses Sequoia PGP in rpm](https://sequoia-pgp.org/blog/2023/04/27/rpm-sequoia/) since version 38. + +(interoperability)= +### Interoperability + +OpenPGP was standardized in 1997 to encourage development of interoperable implementations. This has already been a success early on, but in recent years, there has been [much development of new implementations](major-implementations). + +Historically, interoperability has only been tested in an adhoc manner. Since 2019, the Sequoia project is maintaining and operating the ["OpenPGP interoperability test suite"](https://tests.sequoia-pgp.org/), for more rigorous and systematic testing. The test suite has identified numerous [issues](https://gitlab.com/sequoia-pgp/openpgp-interoperability-test-suite#hall-of-fame). + +## The road ahead + +```{note} +Software and protocol development sometimes skips version numbers due to reasons like internal testing, significant changes, avoiding confusion, marketing decisions, or technical issues. The official successor to OpenPGP version 4 is OpenPGP version 6, detailed below. +``` + +### OpenPGP version 6 + +As of this writing (in 2023), [version 6 of OpenPGP](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/) is approaching publication as an RFC. +The [IETF OpenPGP working group](https://datatracker.ietf.org/wg/openpgp/about/#autoid-1) is focused on updating the cryptographic mechanisms, adding new algorithms, and the deprecation of obsolete algorithms. + +This document describes OpenPGP version 6, while pointing out differences to previous versions that are relevant to application developers. + +Significant support for OpenPGP version 6 has already been achieved for multiple implementations, including: + +- [Bouncy Castle Java](https://github.com/bcgit/bc-java/issues/1421), +- [GopenPGP](https://github.com/ProtonMail/gopenpgp/tree/v3), +- [OpenPGP.js](https://github.com/openpgpjs/openpgpjs/releases/tag/v6.0.0-alpha.0), +- [PGPy](https://github.com/dkg/PGPy/tree/dkg/crypto-refresh), +- [Sequoia PGP](https://gitlab.com/sequoia-pgp/sequoia/-/tree/crypto-refresh). + +Initial efforts to incorporate support for OpenPGP version 6 have been undertaken in the PGPainless and RNP implementations. + +### Post-quantum cryptography in OpenPGP + +There is [ongoing work](https://datatracker.ietf.org/doc/draft-wussler-openpgp-pqc/) to standardize and add support for post-quantum {term}`public-key algorithms` in OpenPGP. This project is funded by the [german "BSI"](https://en.wikipedia.org/wiki/Federal_Office_for_Information_Security). Goals include adding support for post-quantum cryptography to Thunderbird and GnuPG. A [presentation](https://datatracker.ietf.org/meeting/113/materials/slides-113-openpgp-a-post-quantum-approach-for-openpgp-00) was given at [IETF 113](https://datatracker.ietf.org/meeting/113/session/openpgp/). + +## Zooming in: Internal structure of OpenPGP data + +OpenPGP data is internally structured as "packets." We'll look into examples of this internal structure in a series of chapters at the end of this document. + +Getting familiar with the internal format of OpenPGP data provides practical insight into the [RFC](https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/), which describes the internal structure of OpenPGP {term}`packets` in full detail, and may also come in handy for debugging issues. + +(Most of the time, however, we will look at OpenPGP artifacts at a higher level of abstraction.) diff --git a/book/source/pitfalls.md b/book/source/pitfalls.md new file mode 100644 index 0000000..ae611f3 --- /dev/null +++ b/book/source/pitfalls.md @@ -0,0 +1,16 @@ + + +# Pitfalls / Things to keep in mind + +## Key IDs are really not guaranteed to be unique + +Use fingerprints, or expect duplicates + +## Signature Subpackets can have duplicates + +## Packet Nesting can be unreasonable + +- EBNF of allowed packet sequences is complex -> Recommend [stricter](https://mailarchive.ietf.org/arch/msg/openpgp/uepOF6XpSegMO4c59tt9e5H1i4g/) best-practices? diff --git a/book/source/policy.md b/book/source/policy.md new file mode 100644 index 0000000..7ac4cca --- /dev/null +++ b/book/source/policy.md @@ -0,0 +1,11 @@ + + +# Algorithms and Policy + +```{note} + +This section is still about to be written. +``` diff --git a/book/source/private_keys.md b/book/source/private_keys.md new file mode 100644 index 0000000..214ff32 --- /dev/null +++ b/book/source/private_keys.md @@ -0,0 +1,133 @@ + + +# Managing private key material in OpenPGP + +## Overview of private keys + +This chapter discusses the handling of private key material within OpenPGP. + +Private key material is associated with component keys, which are integral parts of [OpenPGP certificates](/certificates). For a discussion of packet structure internals, see the chapter [](zoom/private_keys). + +## Terminology: "certificates" and "private keys" + +Recall that in this document, the term *OpenPGP certificate* refers to what are commonly known as "OpenPGP public keys." OpenPGP certificates are the combination of component public keys, identity components, binding self-signatures, and third-party certifications, +as discussed in the previous chapter ([](/certificates)). + +This chapter focuses on the corresponding counterpart to the elements of certificates: the *private key material* of component keys. + +In this documentation, we treat the private key material as logically separate from the OpenPGP certificate. Operations that use private key material are typically managed by a separate subsystem. It is useful to view OpenPGP certificates and the associated private key material as related but distinct elements[^pkcs11]: + +```{figure} plain_svg/OpenPGPCert_with_privatekeystore.svg +:name: fig-openpgp-certificate-with-private-key-store +:alt: A diagram on a white background showing an OpenPGP certificate and a private keystore. Gray dotted lines connect the green public key symbols of the OpenPGP certificate to red dotted private key symbols in the private keystore. + +An OpenPGP certificate, with the associated private key material handled in a separate subsystem. +``` + +[^pkcs11]: The distinction between certificates (which combine public key material and identity information) and private key material is similarly made in the data model of [PKCS #11](https://en.wikipedia.org/wiki/PKCS_11) cryptographic systems. + +In certain cases, an exception arises where the cryptographic private key material is integrated into the same OpenPGP framing format as the certificate. This is specifically done in the context of transferable secret keys (TSKs). + +## Transferable secret key format + +Sometimes it is useful to handle OpenPGP certificates combined with private key material in the form of a [*transferable secret key (TSK)*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-transferable-secret-keys). A TSK is a serialized format that combines OpenPGP certificate data with its connected private key material, stored in a single file. + +```{figure} plain_svg/TSK.svg +:name: fig-transferable-secret-key +:alt: A box on a white background titled "transferable secret key." It resembles the figure depicting an OpenPGP certificate, except that in each component key box, below the green public key symbol, the red-dotted private key symbol is also shown. + +OpenPGP certificate with integrated private key material, as a TSK +``` + +The TSK format is particularly useful for backups of OpenPGP key material or transferring a key to a different computer[^gpg-tsk]. For insights into the packet structure of a TSK, see the chapter [](zoom/private_keys). + +[^gpg-tsk]: For example, in GnuPG, an OpenPGP key can be exported in (armored) TSK format using the following command: `gpg --export-secret-key --armor `. + +```{admonition} Terminology +:class: note + +Transferable secret keys are sometimes colloquially referred to as "OpenPGP private keys." +``` + +Historically, the concept of TSKs, which combine all elements of an OpenPGP certificate with the associated private key material, has sometimes been conflated with OpenPGP private key operations. However, TSKs are primarily a format for storage and transport; it is generally considered inappropriate as a data structure for use in a private keystore. For further details, see {ref}`key-store-design`. + +(protected-private-keys)= +## Protecting keys with passphrases + +In the OpenPGP format, private key material can be optionally protected with a [passphrase](https://en.wikipedia.org/wiki/Passphrase). + +This method proves effective in scenarios where an unauthorized party obtains the OpenPGP key data but does not know the passphrase. Such a safeguard renders the key unusable to the attacker, effectively protecting it against unauthorized access or use. + +### Transforming passphrases into symmetric keys + +When protecting private key material in OpenPGP, a symmetric key is derived from the user's passphrase. This derived key is then used to protect the OpenPGP private key data. + +To facilitate this, the OpenPGP standard defines a set of mechanisms known as [string-to-key (S2K)](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-string-to-key-s2k-specifier). S2K mechanisms are used to generate high-entropy symmetric encryption keys from lower-entropy passphrases, using a [key derivation function (KDF)](https://en.wikipedia.org/wiki/Key_derivation_function). + +```{figure} plain_svg/passphrase_using_S2K.svg +:name: fig-passphrase-using-s2k +:alt: A diagram on a white background titled "Converting a passphrase into a symmetric key." On the left is a light-yellow box with dotted-yellow borders framing the phrase "correct horse battery staple." A dotted yellow line falls below the box to the term "passphrase." To the right of the box is a light-green arrow with green-dotted borders and the text "S2K mechanism (string-to-key). The arrow points to its right, where a yellow symmetric key symbol is shown. + +Deriving a symmetric key from a passphrase +``` + +This symmetric key is used to protect the private key material it is in a passive state, for example, when stored on disk. To use a passphrase-protected OpenPGP private key, it is first decrypted using the symmetric key and then used for private key operations, remaining temporarily unlocked in memory. + +#### Mechanisms for symmetric key generation + +Over time, OpenPGP has evolved to include various [S2K mechanisms for generating symmetric keys](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-string-to-key-s2k-types-reg), in line with advancements in cryptographic practices. Currently, two mechanisms are universally recommended: + +- [**Argon2**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-argon2): Introduced in OpenPGP version 6, Argon2 is a memory-hard mechanism designed to reduce the efficiency of brute-force attacks using specialized hardware. +- [**Iterated and Salted S2K**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-iterated-and-salted-s2k): This mechanism is a staple with OpenPGP version 4 implementations. + +A third mechanism is conditionally allowed for key generation. Decryption of private keys that use obsolete mechanisms is also allowed. + +The RFC uses the terms "String-to-Key (S2K) specifier" or "String-to-Key (S2K) specifier type" for mechanisms used to *generate* a symmetric key from a passphrase. + +### Using symmetric keys for encryption + +The generation of a symmetric key from a passphrase leads to its subsequent use in encrypting or decrypting OpenPGP private key material. + +The RFC uses the term "String-to-Key Usage (S2K usage)" for the mechanism used to *apply* the symmetric key. + +Different mechanisms are specified [for encryption of OpenPGP private key material](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption). + +### Component-based passphrase protection + +The OpenPGP mechanism for protecting private key material applies individually to each component key: + +- Private key material for individual component keys within a single certificate can be protected with different mechanisms or passphrases. +- Individual component keys may be stored in unprotected form, while others are secured. + +Commonly, when creating a certificate, the user's software will use the same encryption mechanism and passphrase for all component keys. This might give the erroneous impression that all component private key material is encrypted in one, monolithic operation using a single passphrase. + +However, variations are possible, such as when adding new subkeys to an existing certificate. In such cases, a user might choose a different passphrase, or the software might select a different encryption mechanism, for instance, for updated best practices. + +(openpgp-card)= +## OpenPGP cards for private keys + +[OpenPGP cards](https://en.wikipedia.org/wiki/OpenPGP_card) represent a category of hardware security devices specifically designed to handle OpenPGP private key material. These cards offer an alternative to directly managing private key material on the user's computer. + +Hardware security devices, such as OpenPGP cards, are designed to prevent the user's computer from direct access to the private key material. The goal is to make it impossible to exfiltrate the key material, even when a remote attacker has fully compromised the user's system. + +OpenPGP cards adhere to an open specification detailed in the [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). This specification has been implemented by multiple vendors across various devices, with several Free Software versions available, some of which are compatible with open hardware designs. + +Effectively, the OpenPGP card specification outlines one model for a private keystore subsystem. OpenPGP cards do not store a full OpenPGP certificate. Instead, they have three distinct "key slots" designated for *signing*, *decryption*, and *authentication*. Each key slot stores the data of one component key[^missing-ecdh], including its cryptographic private key material. Additionally, OpenPGP cards explicitly store the fingerprint of each component key within the corresponding key slot. + +[^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 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 stored OpenPGP fingerprint on the card. + +Notably, the practice of explicitly storing fingerprints on OpenPGP cards contrasts with the general OpenPGP format, where fingerprints of component keys are not stored but are instead dynamically calculated from the key data. + +## Private key operations + +Although OpenPGP encompasses a broad range of cryptographic mechanisms, the set of operations performed within the core of a private keystore are simple and very limited. + +Specifically, an OpenPGP private keystore implements two primitives: + +1. Given private key material whose algorithm supports decryption, it can decrypt a *session key*. +2. Given private key material whose algorithm supports signing, it can calculate a *cryptographic signature* for a hash digest. + +These essential operations require access only to the component keys and their associated private key material, specifically [Secret-Key packets](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats). Additional packets, such as binding signatures, are not required. diff --git a/book/source/signatures.md b/book/source/signatures.md new file mode 100644 index 0000000..c1039b6 --- /dev/null +++ b/book/source/signatures.md @@ -0,0 +1,158 @@ + + +# OpenPGP Signatures + +{term}`Signatures` are a fundamental mechanism within OpenPGP. They provide the syntax for forming and interpreting comprehensive statements about {term}`certificates` and their {term}`components`, as well as for ensuring the integrity and {term}`authenticity` of data. + +Without {term}`signatures`, {term}`keys` would remain unassociated with any {term}`certificate` or {term}`owner`. {term}`Signatures` are crucial for binding {term}`component keys` and {term}`identity components` into hierarchical {term}`certificates` and for establishing the {term}`authenticity` of messages. + +## Terminology: "cryptographic signatures" and "signature packets" + +Within OpenPGP, the term *{term}`signature`* can have two different meanings: + +- **{term}`Cryptographic signature`**: a sequence of bytes created by {term}`cryptographic keys`, calculated according to a {term}`signature` scheme. + +```{figure} plain_svg/cryptographic_signature.svg +:name: fig-cryptographic-signature +:alt: Depicts a box on white background. In the box, a green seal symbol with the word "sig" is shown on the left side, connected to the text "Cryptographic signature" by a black dotted line. + +A {term}`cryptographic signature` +``` + +- **{term}`OpenPGP signature packets`**: Defined in the [OpenPGP standard](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-packet-type-id-2), these {term}`packets` combine a raw {term}`cryptographic signature` along with a *{term}`type`* designation and additional {term}`metadata`. + +```{figure} plain_svg/OpenPGP_Signature_packet.svg +:name: fig-signature-packet-0 +:alt: Depicts a box on white background. In the top, the text OpenPGP signature packet is connected to a dotted box. Inside a yellow box is shown. It has the title "signature metadata" and two lines of content, reading "signature type" and "additional metadata". The yellow box is labeled with the green cryptographic signature symbol. The green symbol is labeled with a dotted line and the text "Cyptographic signature" to its right. On the left side of the box, connected with a dotted line, a small cion-sized representation of the yellow signature packet and its green cryptographic signature are shown. This introducedthe equivalence of the two representations. + +An "{term}`OpenPGP Signature Packet`" +``` + +In this document, "{term}`signature`" will refer to {term}`OpenPGP signature packets`. + +(signature-types)= +## Signature types 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 *{term}`signature type ID`*. {term}`Signature types` define the purpose of a {term}`signature packet` and how it should be interpreted. + +{term}`Signature types` can be predominantly classified in two ways: + +- **{term}`Signatures over data`**: These signatures are denoted by {term}`type IDs` `0x00` for binary documents and `0x01` for canonical text documents. The {term}`signer` uses these {term}`signatures` to claim ownership, assert creation, or certify the immutability of the document. +- **{term}`Signatures on components`**: These are {term}`signatures` that are associated with {term}`component keys` or {term}`identity components` of a {term}`certificate`. + +{term}`Signatures on components` are a complex topic, and we discuss them in depth in [](/signing_components). They are grouped based on two criteria: + +- the origin of the {term}`signature`, distinguishing between a {term}`self-signature` and a {term}`third-party signature` +- the nature of the statement made by the {term}`signature`, such as certifying an {term}`identity` or binding {term}`component keys` into a {term}`certificate` + +```{figure} img/mermaid/sig-types.png +:name: fig-signature-types +:alt: Depicts a diagram, describing different types of OpenPGP signatures. On the right hand side a long yellow box with the title "Signature Types and Targets" is shown, which contains signature type IDs and their names (in gray boxes) and further yellow boxes, grouping other types of signature type IDs. At the top the signature type ID "0x02 Standalone" is shown. Below, another yellow box groups the "Signature Packet"s "0x50 Third-Party Confirmation" and "0x40 Timestamp". Another box groups types of signatures, that apply to "Data" packets "0x00 Binary Data" and "0x01 Canonical Text". Below, a box groups types of signatures, that apply to "Primary Key + User ID/ Attr. Packet"s. The type IDs "0x10 Generic Certification", "0x11 Persona Certification", "0x12 Casual Certification" and "0x13 Positive Certification" are shown together in one gray box and "0x30 Certification Revocation" in another. Another yellow box groups types of signatures, that apply to "Primary Key" packets "0x1F Direct-Key Signature" and "0x20 Key Revocation". The last box groups types of signatures, that apply to "Primary + Subkey" packets. "0x18 Subkey Binding" and "0x19 Primary Key Binding" are shown together in one gray box, "0x28 Subkey Revocation" in another. On the left hand side of the diagram shows gray boxes identifying different types of signatures, with the most basic being "OpenPGP Signature" on the far left. With arrows it points to further signature types ("Signature on Data", "Signature on Component") and several signature type IDs ("0x02", "0x50" and "0x40"). The signature type "Signature on Data" points to "0x00" and "0x01". The signature type "Signature on Component" points to two more specific signature types, namely "Third-Party" and "Self-Signature". "Third-Party" points at the group of "0x10", "0x11", "0x12" and "0x13", as well as "0x30" and "0x1F". "Self-Signature" points at the group of "0x10", "0x11", "0x12" and "0x13", as well as "0x30", "0x1F", the group of "0x18" and "0x19" and finally "0x28". + +An overview of {term}`signature types` in OpenPGP +``` + +This chapter will cover the overarching principles applicable to all {term}`OpenPGP signature types`. + +For more detail about specific {term}`types of signatures`, see the chapters on [](/signing_data) and [](/signing_components), respectively. + +## Structure of an OpenPGP signature packet + +As outlined above, an {term}`OpenPGP signature` is a composite data structure, which combines: + +- **{term}`Signature type ID`**: specifies the {term}`signature`'s intended meaning, as detailed above +- **{term}`Metadata`**: varies based, in part, on the {term}`signature type ID`; mostly encoded as "{term}`subpackets`" (see {ref}`signature-subpackets`) +- **Raw {term}`cryptographic signature`** + +```{figure} plain_svg/OpenPGP_Signature_packet_2.svg +:name: fig-signature-packet +:alt: Depicts a diagram with the title "OpenPGP signature packet". A box with green dotted frame and white background provides the title "Signature", while inside the box the text reads "Signature over; Input data, Signature metadata". The words "Signature metadata" serve as title for a yellow box at the lower half of the signature type box. The yellow box also bears the green cryptographic signature symbol. + +Structure and context of an {term}`OpenPGP signature packet` +``` + +The input data packets differ between specific signature types. Also see {numref}`fig-signature-types`. For example: + +- for a [*binary data signature*](data-signature-types), the input data packet is a *literal data packet*, while +- for a [*subkey binding signature*](bind-subkey), the input data packets consist of a primary and a subkey packet. + +### Creating an OpenPGP signature packet + +Creating an {term}`OpenPGP signature packet` involves encoding a statement about a specific set of data within the {term}`packet`. + +The input data of a {term}`signature packet` includes: + +- **{term}`Packets` being signed**: Typically one or more {term}`packets`, though sometimes none, depending on the context. These are the {term}`packets` to which the signature statement pertains. +- **Data within the {term}`signature packet`**: This includes information that specifies the intent of the {term}`signature`. + +The input data is determined by the {term}`signature type` and consists of the exact content that the signature statement addresses. + +The {term}`signature packet` consists of two parts: + +1. **Statement definition**: This part of the {term}`packet` defines the meaning or intent of the {term}`signature`. +2. **{term}`Cryptographic signature`**: This is the formal endorsement by the {term}`signer`, created as follows: + - A {term}`hash digest` is calculated from the input data. + - The {term}`cryptographic signature` is then calculated for this {term}`hash digest`. + +```{figure} plain_svg/Signature_Creation.svg +:name: fig-signature-creation +:alt: Depicts a complex diagram with white background and the title "Signature creation". On the top left side a box with black frame and white background reads "Input Data packets, One or more packets". Below it the symbol of a signature packet is shown (however, instead of the green signature symbol, only a circle with white background and dotted frame is shown). Both are connected (via green dotted arrows) to a green, right pointing arrow symbol with green dotted frame and the title "Hash mechanism". Text above the green arrow symbol reads "A hash digest is calculated from the input data packets and the signature metadata". The "Hash mechanism" arrow points at a box with white background and green frame, which reads "hash digest". At the top right corner of the diagram the symbol for a component key with both public and private key and the title "Signer private key" is shown. Both hash digest and component key symbol point to a large green arrow symbol, with green dotted frame, at the lower right corner of the diagram, using green dotted arrow lines. The large arrow symbol has the title "Signing mechanism" and text overlaid across it reads "A cryptographic signature is calculated over the hash digest, using the private key material of the signer.". It points at a cryptographic signature symbol at the bottom of the diagram. The cryptographic signature symbol is connected (via a green dotted arrow line) to the circle with white background and dotted green frame in the signature packet symbol. + +Creating a {term}`signature` in OpenPGP +``` + +(signature-verify)= +### Verifying an OpenPGP signature packet + +Verifying an {term}`OpenPGP signature packet` is similar to its creation, with some crucial differences that facilitate the {term}`verification` by entities other than the {term}`signer`. + +The main differences: + +- **Access to {term}`public key`**: Unlike the creation process, which is exclusive to the {term}`signer`, {term}`verification` can be performed by anyone who has access to the {term}`public key` of the {term}`signer`. +- **Use of {term}`signature verification` mechanism**: +After calculating the {term}`hash digest` from the input data, a {term}`signature verification` mechanism is employed. This mechanism uses the {term}`hash digest`, the {term}`cryptographic signature` from the {term}`signature packet`, and the {term}`public key` of the {term}`signer`. Its purpose is to ascertain the cryptographic {term}`validity` of the {term}`signature`. + +```{figure} plain_svg/Signature_Verification.svg +:name: fig-signature-verification +:alt: Depicts a complex diagram with white background and the title "Signature verification". On the top left side a box with black frame and white background reads "Input Data packets, One or more packets". Below it the symbol of a signature packet is shown. Both are connected (via green dotted arrows) to a green, right pointing arrow symbol with green dotted frame and the title "Hash mechanism". Text above the green arrow symbol reads "A hash digest is calculated from the input data packates and the signature metadata". The "Hash mechanism" arrow points at a box with white background and green frame, which reads "hash digest". At the top right corner of the diagram the symbol for a component key with only public key and the title "Signer public key" is shown. Hash digest, component key symbol and the cryptographic signature symbol in the signature packet point to a large green arrow symbol, with green dotted frame, at the lower right corner of the diagram, using green dotted arrow lines. The large arrow symbol has the title "Signature verification mechanism" and text overlaid across it reads "A cryptographic signature is verified against the hash digest, using the public key of the signer.". It points at a success and fail symbol at the bottom of the diagram. + +Verifying a {term}`signature` in OpenPGP +``` + +(signature-subpackets)= +## Signature subpackets + +In the OpenPGP protocol, {term}`signature subpackets` enhance the expressiveness of a {term}`signature` beyond what is conveyed by just the bare {term}`cryptographic signature` and the {term}`signature type ID`. These {term}`subpackets`, introduced in [RFC 2440](https://datatracker.ietf.org/doc/html/rfc2440), are essential for embedding additional {term}`metadata` within {term}`signature packets`. + +{term}`Signature subpackets` serve as sub-elements within {term}`signature packets`, providing extra context and meaning to a {term}`signature`. +They are formatted as key-value pairs, where the keys are defined as [subpacket type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-subpacket-types-r) by the {term}`RFC`. The {term}`RFC` also provides the format and interpretation of the values. + +### Examples of signature subpackets +- The [*issuer fingerprint*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#issuer-fingerprint-subpacket) {term}`subpacket` encodes the {term}`fingerprint` of the {term}`component key` that issued the {term}`signature`. +- The [*key flags*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) {term}`subpacket` defines the {term}`capabilities` that are assigned to a {term}`component key` within a {term}`certificate`. + +(subpacket-areas)= +### Hashed and unhashed signature subpackets + +{term}`Signature subpackets` within OpenPGP can reside in one of two distinct areas of a {term}`signature packet`, each serving a different purpose. + +- **{term}`Hashed area`**: {term}`Hashed subpackets` are included in the {term}`hash digest` of the {term}`signature` and are thus covered by its {term}`cryptographic signature`. They reliably express the {term}`signer`'s intent. +- **{term}`Unhashed area`**: {term}`Unhashed subpackets`, conversely, are not included in the {term}`hash digest` for the {term}`signature`. They are thus not protected against tampering and can be used to retroactively add, change, or remove metadata in a {term}`signature packet` without affecting its {term}`validity`. They are primarily used for advisory purposes or in scenarios where the integrity of the {term}`subpacket` content can be self-authenticated. An example is the {term}`issuer fingerprint subpacket`, which can be {term}`validated` through successful {term}`signature verification` using the referenced {term}`issuer key`. + +The majority of {term}`signature subpackets` are stored in the {term}`hashed area`. + +For detailed information and specifications, refer to [Hashed vs. Unhashed Subpackets](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-hashed-vs-unhashed-subpacke) in the OpenPGP {term}`RFC`. + +(criticality-of-subpackets)= +### Criticality of subpackets + +In the OpenPGP protocol, each {term}`signature subpacket` can be marked with a *{term}`criticality flag`*. This flag plays a pivotal role in the interpretation and {term}`validation` of the {term}`signature`. When set, it instructs any receiving {term}`implementation` encountering an unrecognized {term}`subpacket type` to treat this as a significant error and to {term}`invalidate` the {term}`signature`. + +This mechanism accounts for different {term}`OpenPGP implementations` that may support only certain subsets of the standard. Moreover, it anticipates the evolution of the standard, including the addition of new {term}`subpacket types`. + +Consider a scenario where an {term}`implementation` does not recognize a {term}`subpacket` indicating {term}`signature` {term}`expiration`. Without understanding this concept, the {term}`implementation` might erroneously accept an already {term}`expired` {term}`signature`. By marking the {term}`signature expiration time subpacket` as {term}`critical`, the creator of the {term}`signature` ensures that any recipient who cannot process this {term}`subpacket` will reject the {term}`signature` as {term}`invalid`. + +For specific guidelines on which {term}`subpackets` should be marked as {term}`critical`, refer to the {term}`RFC` sections [5.2.3.11](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-creation-time) to [5.2.3.36](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-intended-recipient-fingerpr). diff --git a/book/source/signing_components.md b/book/source/signing_components.md new file mode 100644 index 0000000..7067a09 --- /dev/null +++ b/book/source/signing_components.md @@ -0,0 +1,277 @@ + + +# Signatures on components + +This chapter examines {term}`OpenPGP signatures` associated with {term}`certificate components`, applying to: + +- {term}`component keys`, encompassing {term}`primary keys` and {term}`subkeys` +- {term}`identity components`, namely {term}`User IDs` and {term}`User attributes` + +{term}`Signatures on components` are used to construct and maintain {term}`certificates`, and to model the {term}`authentication` of {term}`identities`. + +This chapter expands on topics introduced in the [](certificates) chapter. + +## Self-signatures vs third-party signatures + +{term}`Component signatures` in OpenPGP are categorized into two distinct types: + +- **{term}`self-signatures`**, which are issued by the {term}`certificate holder` using the {term}`certificate`'s {term}`primary key` +- **{term}`third-party signatures`**, which are issued by an external entity, not the {term}`certificate holder` + +(self-signatures)= +### Self-signatures + +{term}`Self-signatures` are fundamental in creating and managing {term}`OpenPGP certificates`. They bind the various {term}`components` of a {term}`certificate` into one combined data structure and facilitate the {term}`certificate`'s {term}`life-cycle management`. + +{term}`Life-cycle management` operations include: + +- {term}`binding` additional {term}`components` to a {term}`certificate` +- modifying {term}`expiration time` or other {term}`metadata` of `components` +- revoking, and thus invalidating, {term}`components` or existing {term}`self-signatures` + +{term}`Self-signatures` are issued by the {term}`certificate's owner` using the {term}`certificate`'s {term}`primary key`. + +```{note} +No [key flag](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) is required to issue {term}`self-signatures`. An {term}`OpenPGP primary key` can issue {term}`self-signatures` by default. +``` + +### Third-party signatures + +{term}`Third-party signatures` are pivotal in OpenPGP for decentralized {term}`authentication`, forming the basis of the {term}`Web of Trust`. They encode {term}`authentication`-related statements about {term}`certificates` and linked {term}`identities`, establishing trustworthiness of {term}`identity claims`. + +Third-party signatures are used to make specific statements: + +- {term}`certifying` {term}`identity claims` +- {term}`delegating` {term}`authentication` decisions +- {term}`revoking`, and thus {term}`invalidating`, prior {term}`third-party signature` statements + +```{note} +The **{term}`certify others`** [key flag](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags) (`0x01`) is required to issue {term}`third-party signatures`. By convention[^primary-certification], only the {term}`certificate`'s {term}`primary key` can hold this {term}`key flag`. +``` + +[^primary-certification]: Most current {term}`implementations` assume that only the {term}`primary key` may hold the *{term}`certify others`* {term}`key flag`, although this is not specified in the {term}`RFC`. + +### Distinct functions of self-signatures and third-party signatures + +The meaning of an {term}`OpenPGP signature` depends significantly on its {term}`issuer`. {term}`Self-signatures` and {term}`third-party signatures`, even when of the same [signature type](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-types), serve distinct functions. For example: + +- {term}`Certifying self-signatures` ({term}`type IDs` `0x10` - `0x13`) bind a {term}`User ID` to a {term}`certificate`. +- {term}`Third-party signatures` of the same {term}`type IDs` endorse the {term}`authenticity` of a {term}`User ID` on another user's {term}`certificate`. + +In another instance: + +- *When issued as a {term}`self-signature`*, a [direct key signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-direct-key-signature-type-i) sets {term}`preferences` and advertises {term}`features` applicable to the entire {term}`certificate`. +- *When issued by a {term}`third party`*, especially when it carries a [trust signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-trust-signature) {term}`subpacket`, a similar {term}`direct key signature` {term}`delegates` trust to the signed {term}`certificate`. This may designate the signed {term}`certificate` as a {term}`trust anchor` within the {term}`issuer`'s {term}`Web of Trust`. + +(binding-signatures)= +## Self-signatures in certificate formation and management + +{term}`Self-signatures` play a crucial role in forming and managing the structure of {term}`OpenPGP certificates`. These act as *{term}`binding signatures`*, joining {term}`components` and embedding {term}`metadata`. + +Internally, an {term}`OpenPGP certificate` is essentially a series of {term}`packets` strung sequentially. When a {term}`certificate` is stored in a file format known as a [transferable public key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-transferable-public-keys), {term}`packets` can be easily added or removed. + +To safeguard against unauthorized additions or alterations of {term}`components`, OpenPGP uses {term}`cryptographic signatures`. These validate that all {term}`components`, such as {term}`subkeys` or [identity components](identity-components), were linked to the {term}`OpenPGP certificate` by its {term}`owner`, using the {term}`primary key`. While anyone can still store unrelated elements to a {term}`certificate` dataset, {term}`OpenPGP implementations` will reject them if they lack a {term}`valid` cryptographic connection with the {term}`certificate`. + +```{note} +Conversely, omissions of {term}`packets` by third parties can easily occur when handling an {term}`OpenPGP certificate` dataset. This could pose a challenge, for example, when an attacker deliberately omits {term}`revocation` {term}`packets`. Without access to an alternative, complete {term}`certificate` source, recipients might not detect these omissions. +``` + +However, there are legitimate instances in which third parties add "unbound" {term}`packets` (i.e., not signed by the {term}`certificate`'s {term}`owner`) to a {term}`certificate`: + +- [Third-party certifications](third-party-certifications) are often stored within the {term}`packet` data of the {term}`certificate` to which they are related. This is a standard practice that provides convenience for users by allowing easy access to all relevant {term}`certifications`. (See [](keyserver-flooding) for discussion of a related pitfall.) +- {term}`OpenPGP software` may locally add [unbound identity data](unbound-user-ids) to a {term}`certificate`. + +(bind-subkey)= +### Binding subkeys to a certificate + +{term}`Subkeys` are linked to {term}`OpenPGP certificates` via a [subkey binding signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#sigtype-subkey-binding) ({term}`type ID` `0x18`). This {term}`signature type` indicates the association of the {term}`primary key` with the {term}`subkey`. + +A {term}`subkey binding signature` binds a {term}`subkey` to a {term}`primary key`, and it embeds {term}`metadata` into the {term}`signature packet`. Once generated, the {term}`subkey binding signature` {term}`packet` is stored in the {term}`certificate` directly after the {term}`subkey` it binds. + +{term}`Subkeys` designated for signing purposes, identified by the *{term}`signing`* [key flag](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags), represent a unique category and are handled differently. See {numref}`bind-signing-subkey`. + +```{figure} plain_svg/subkey_binding_signature.svg +:name: fig-subkey-binding-signature +:alt: Depicts a diagram on white background with the title "Subkey binding signature". At the top left the symbol of a primary component key with certification capability is shown. At the bottom left the symbol of a component key with encryption capability is shown. The primary component key points at the lower component key with a full green arrow line. In the middle of the connection the small symbol of a signature packet is shown. On the right side of the diagram a detailed version of the signature packet can be found in a box with the title "Subkey binding signature". The text reads "Signature over Primary key, Subkey" and the box with "Signature metadata" contains the list "signature creation time", "key expiration time", "key flags" and "issuer fingerprint". The primary component key points at the detailed signature packet with a dotted green arrow line and the text "Primary key creates a subkey binding signature to bind the subkey to the primary key". + +Linking an {term}`OpenPGP subkey` to the {term}`primary key` with a {term}`binding signature` +``` + +{term}`Metadata` for the {term}`subkey`, such as the [*key expiration time*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#key-expiration-subpacket) and {term}`capabilities` set by [*key flags*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#key-flags), are included in {term}`subpackets` within the {term}`subkey binding signature` {term}`packet`. + +```{note} +The {term}`validity` of a {term}`subkey` is intrinsically linked to that of the {term}`primary key`. An {term}`expired` {term}`primary key` renders any associated {term}`subkey` {term}`invalid`, regardless of the {term}`subkey`'s own {term}`expiration` setting. + +Legally, a {term}`subkey` may not have a specified {term}`expiration time`. In such cases, its {term}`expiration` aligns implicitly with that of the {term}`primary key`. Additionally, the {term}`creation time` of a {term}`subkey` must always be more recent than that of the {term}`primary key`. +``` + +(bind-signing-subkey)= +### Special case: Binding signing subkeys + +{term}`Binding` {term}`subkeys` that possess the *{term}`signing`* {term}`key flag` to a {term}`certificate` represents a unique scenario. While similar to the {term}`binding process` of other {term}`subkeys`, there is an additional, critical requirement: mutual association. + +That is, to bind a {term}`signing-capable` {term}`subkey` to a {term}`primary key`, it is insufficient that the "{term}`primary key` wants to be associated with the {term}`subkey`." The {term}`subkey` must explicitly signal that it "wants to be associated with the {term}`primary key`." + +This mutual binding is crucial for security. Without it, an individual (e.g., Alice) could falsely claim a connection to another person's (e.g., Bob's) {term}`signing subkey`. +Alice could thus claim to have issued {term}`signatures` which were actually issued by Bob. +To prevent such scenarios, where an attacker might wrongfully "adopt" a victim's {term}`signing subkey`, a dual-layer of {term}`signatures` is used: + +- the [subkey binding signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#sigtype-subkey-binding) ({term}`type ID` `0x18`), which is issued by the {term}`certificate`'s {term}`primary key` +- the [primary key binding signature](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#sigtype-primary-binding) ({term}`type ID` `0x19`), created by the {term}`subkey` itself. This is informally known as an embedded "{term}`back signature`," because the {term}`subkey`'s {term}`signature` points back to the {term}`primary key`. + +```{figure} plain_svg/subkey_binding_signatur_for_signing_sk.svg +:name: fig-subkey-binding-signature-for-signing-subkeys +:alt: Depicts a diagram on white background with the title "Subkey binding signature for signing subkeys". At the top left the symbol of a primary component key with certification capability is shown. At the bottom left the symbol of a component key with signing capability is shown. The primary component key points at the lower component key with a full green arrow line. In the middle of the connection the small symbol of a signature packet is shown. On the right side of the diagram a detailed version of the signature packet can be found in a box with the title "Subkey binding signature". The text reads "Signature over Primary key, Subkey" and the box with "Signature metadata" in it contains the list "signature creation time", "key expiration time", "key flags" and "issuer fingerprint". Within the signature metadata a box with a green dotted frame extends the list with an inlined signature packet with the title "Embedded Signature; Primary key binding". Its inner text reads "Signature over Primary Key, Signing Subkey". The signature metadata area of this embedded signature holds the list "signature creation time" and "issuer fingerprint". The cryptographic signature symbol overlaps both metadata and general section of the embedded signature. From the signing component key a green dotted arrow line points to the embedded signature in the subkey binding signature with the text "Signing key creates a primary binding signature to associate itself with the primary key" ("primary binding signature" in bold). At the top of the diagram, the primary component key points at the detailed signature packet with a dotted green arrow line and the text "Primary key creates a subkey binding signature to bind the subkey to the primary key". + +Linking an {term}`OpenPGP signing subkey` to the {term}`primary key` with a {term}`binding signature`, and an embedded {term}`primary key binding signature` +``` + +The {term}`back signature` signifies the mutuality of the {term}`subkey`'s association with the {term}`primary key` and is embedded as {term}`subpacket` data within the {term}`subkey binding signature`, reinforcing the {term}`authenticity` of the {term}`binding`. + +(bind-identity)= +### Binding identities to a certificate + +{term}`Self-signatures` also play a vital role in {term}`binding` {term}`identity components`, such as {term}`User IDs` or {term}`User Attributes`, to an {term}`OpenPGP certificate`. + +To bind the {term}`User ID` `Alice Adams ` to her {term}`OpenPGP certificate` (`AAA1 8CBB 2546 85C5 8358 3205 63FD 37B6 7F33 00F9 FB0E C457 378C D29F 1026 98B3`), Alice would use a {term}`certification signature`. + +There are four types of *{term}`certifying self-signature`*. The most commonly used {term}`type` for {term}`binding` {term}`User IDs` is the [positive certification](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#sigtype-positive-cert) ({term}`type ID` `0x13`). Alternatively, {term}`type` `0x10`, `0x11`, or `0x12` might be used. This {term}`binding signature` must be issued by the {term}`primary key`. + +The {term}`certifying self-signature` {term}`packet` – calculated over the {term}`primary key`, {term}`User ID`, and {term}`metadata` of the {term}`signature packet` – is added to the {term}`certificate`, directly following the {term}`User ID` {term}`packet`. + +```{figure} plain_svg/user_id_certification.svg +:name: fig-user-id-certification +:alt: Depicts a diagram on white background with the title "User ID binding signature". At the top left the symbol of a primary component key with certification capability is shown. At the bottom left the symbol of a User ID reads "Alice Adams ". The primary component key points at the User ID with a full green arrow line. In the middle of the connection the small symbol of a signature packet is shown. On the right side of the diagram a detailed version of the signature packet can be found in a box with the title "User ID binding signature". The text reads "Signature over Primary key, User ID" and the box with "Signature metadata" in it contains the list "signature creation time", "key expiration time", "primary User ID flag", "algorithm preferences", "key expiration time (primary key)" and "key flags (primary key)". At the top of the diagram, the primary component key points at the detailed signature packet with a dotted green arrow line and the text "Primary key creates a User ID binding signature to associate the User ID with the primary key". + +Linking a {term}`User ID` to an {term}`OpenPGP certificate` +``` + +(primary-metadata)= +### Adding global metadata to a certificate + +The {term}`signatures` that {term}`bind` {term}`subkeys` and {term}`identity components` to a {term}`certificate` serve dual purposes: linking {term}`components` to the {term}`certificate` and adding {term}`metadata` to {term}`components`. + +While it is essential to add {term}`metadata` that pertains to the entire {term}`certificate`, this does not require {term}`binding` any {term}`component` to the {term}`certificate`. In this case, the {term}`signature` mechanism is used just to associate {term}`metadata` with the {term}`certificate` globally. + +Two {term}`signature types` can perform this function: + +- {term}`direct key signature` on the {term}`primary key` +- {term}`primary User ID binding signature` + +The types of {term}`metadata` typically associated with the {term}`certificate` through these methods include: + +- {term}`key` {term}`expiration` +- {term}`key flags` ({term}`capabilities`) +- {term}`features` +- {term}`algorithm preferences` signaling + +(direct-key-signature)= +#### Direct key signature + +A [*direct key signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-direct-key-signature-type-i) serves as the [preferred mechanism](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-5.2.3.10-9) in OpenPGP v6 for defining {term}`metadata` for the entire {term}`certificate`, by associating it with the {term}`primary key`. + +(primary-user-id-binding)= +#### Self-signature binding to primary User ID + +In OpenPGP v4, another mechanism was often used for {term}`metadata` management: integrating global {term}`certificate` {term}`metadata` within a {term}`User ID binding signature`. This is specifically evident in the {term}`binding signature` of the [*primary* User ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-primary-user-id) of the {term}`OpenPGP certificate`. + +This method results in the {term}`primary User ID binding signature` containing a mix of {term}`metadata`: some specific to that {term}`User ID` and some applicable to the {term}`certificate` globally. + +Given the widespread adoption of this mechanism in existing {term}`OpenPGP certificates`, it is crucial that {term}`OpenPGP applications` recognize and manage it. + +(self-revocations)= +### Revocation self-signatures: Invalidating certificate components + +{term}`Revocation self-signatures` represent an important class of {term}`self-signatures`, used primarily to invalidate {term}`components` or retract prior {term}`signature` statements. + +There are several types of {term}`revocation signatures`, each serving a specific purpose: + +- A [**key revocation signature**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-revocation-signature-ty) ({term}`type ID` `0x20`) marks a {term}`primary key` as {term}`revoked`. +- A [**subkey revocation signature**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-subkey-revocation-signature) ({term}`type ID` `0x28`) {term}`invalidates` the {term}`binding of a subkey`. +- A [**certification revocation**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-certification-revocation-si) ({term}`type ID` `0x30`) {term}`invalidates` the {term}`binding` of a {term}`User ID` or {term}`User Attribute`. + +Common scenarios for using {term}`revocations` include marking {term}`certificates` or individual {term}`subkeys` as unusable (e.g., when the {term}`private key` has been compromised or replaced) or declaring {term}`User IDs` as no longer {term}`valid`. + +```{note} +{term}`OpenPGP certificates` act as append-only data structures in practice. Once elements of a {term}`certificate` are published, they cannot be removed from {term}`key servers` or third-party OpenPGP systems. {term}`Implementations` usually merge all available {term}`components` and {term}`signatures`. + +{term}`Revocations` are used to mark {term}`components` or {term}`signatures` as {term}`invalid`. +``` + +Note: {term}`certification signatures` [can be made irrevocable](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-revocable). + +(hard-vs-soft-revocations)= +#### Hard vs soft revocations + +{term}`Revocation signatures` often include a [*Reason for Revocation* subpacket](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-reason-for-revocation), with a code specifying *why* the {term}`revocation` was issued. This code determines whether the {term}`revocation` is considered *soft* or *hard*. + +- **{term}`Soft revocation`**: This is typically used for graceful or planned {term}`invalidation` of {term}`components`, such as retiring or updating {term}`components`. It {term}`invalidates` the {term}`component` from the {term}`revocation signature`'s {term}`creation time`, but earlier uses remain {term}`valid`. Soft revocations can be reversed with a new {term}`self-signature`. +- **{term}`Hard revocation`**: This irrevocably invalidates the {term}`component`, affecting all past and future uses. It is typically used to signal compromise of {term}`secret key material`. + +```{note} +A {term}`revocation signature packet` lacking a {term}`Reason for Revocation subpacket` is interpreted as a {term}`hard revocation`. +``` + +(third-party-certifications)= +## Authentication and delegation in third-party signatures + +{term}`Third-party signatures` in OpenPGP primarily encode {term}`authentication` statements for {term}`identities` and {term}`delegate` trust decisions. These {term}`signatures` can be manually inspected or processed as machine-readable artifacts by {term}`OpenPGP software`, which evaluates the {term}`authenticity` of {term}`certificates` based on user-specified {term}`trust anchors`. + +### Certifying identity components + +When a {term}`signer` issues a {term}`certifying signature` on an {term}`identity`, it indicates a verified link between the {term}`identity` and the {term}`certificate`. That is, the {term}`signer` vouches for the {term}`identity claim`. + +For example, Alice can vouch that Bob's {term}`User ID` `Bob Baker ` is legitimately linked with his {term}`certificate` `BB28 9FB7 A68D BFA8 C384 CCCD E205 8E02 D9C6 CD2F 3C7C 56AE 7FB5 3D97 1170 BA83`, by creating a {term}`certification signature`. Bob can then distribute Alice's `certifying signature` as part of his {term}`certificate`. + +Other users may or may not decide to rely on Alice's statement to determine the {term}`authenticity` of Bob's {term}`certificate`. + +(delegation)= +### Trust signatures: delegating authentication + +OpenPGP uses [*trust signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#trust-signature-subpacket) {term}`subpackets` to {term}`delegate` {term}`authentication` decisions, designating the recipient {term}`certificate` as a "{term}`trusted introducer`" (or a {term}`trust anchor`) for the user. This includes specifying {term}`trust depth` (or level) for transitive {term}`delegations` and quantifying trust with numerical values, indicating the extent of reliance on the {term}`introducer`'s {term}`certifications`. + +{term}`Trust signature` {term}`subpackets` are applicable in {term}`third-party signatures`, more specifically: + +- {term}`identity certification signatures` ({term}`type ID` `0x10` - `0x13`) +- [direct key signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-direct-key-signature-type-i) ({term}`type ID` `0x1F`) + +(trust-level)= +#### Trust depth/level + +The "{term}`trust depth`" (or {term}`level`) in OpenPGP signifies the extent of transitive {term}`delegation` within the {term}`authentication` process. It determines how far a {term}`delegation` can be extended from the original {term}`trusted introducer` to subsequent intermediaries. Essentially, a {term}`certificate` with a {term}`trust depth` of more than one acts as a "{term}`meta-introducer`," facilitating {term}`authentication` decisions across multiple levels in the network. + +A {term}`trust depth` of 1 means relying on {term}`certifications` made directly by the {term}`trusted introducer`. The user's OpenPGP software will accept {term}`certifications` made directly by the {term}`introducer` for {term}`authenticating` identities. + +However, when the {term}`trust depth` is set higher, it implies a chain of {term}`delegation` may extend beyond the {term}`initial introducer`. The user's software will recognize and accept {term}`certifications` made not only by the {term}`primary introducer` but also by other intermediaries whom the {term}`primary introducer` designated as {term}`trusted introducers`. + +This allows for a more extensive network of trusted {term}`certifications`, enabling a broader and more interconnected {term}`Web of Trust`. + +(trust-amount)= +#### Trust amounts + +The "{term}`trust amount`," with a numerical value ranging from `0` to `255`, quantifies the degree of reliance on a {term}`delegation`. + +A higher value indicates greater degree of reliance. This quantification aids {term}`OpenPGP software` in determining an aggregate amount of reliance, based on combined {term}`certifications` from multiple {term}`trusted introducers`. + +(trust-scope)= +#### Limiting delegation scope + +When using *{term}`trust signature`* {term}`subpackets`, a {term}`delegation` can be limited to {term}`identities` that match a [*regular expression*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#regex-subpacket). + +With this mechanism, for example, it is possible to {term}`delegate` {term}`authentication` decisions only for {term}`User IDs` that match the email domain of an organization. + +(wot)= +### Web of Trust: Decentralized trust decisions + +The {term}`Web of Trust` in OpenPGP is a {term}`trust model` that facilitates {term}`authentication` decisions through a network of {term}`certifications` and {term}`delegations`. It is characterized by a so-called [strong set](https://en.wikipedia.org/wiki/Web_of_trust#Strong_set), which refers to a group of {term}`certificates` that are robustly interconnected via `third-party certifications`. + +In this model, users independently {term}`delegate` {term}`authentication` decisions, choosing whose {term}`certification` to rely on. This {term}`delegation` is based on the {term}`certificates` and {term}`third-party signatures` available to them, with their {term}`OpenPGP software` applying the {term}`Web of Trust` mechanism to discern the reliability of each {term}`certificate` for an {term}`identity`. + +The {term}`OpenPGP RFC` doesn't specify exactly how {term}`Web of Trust` calculations are performed. It only defines the data formats on which these calculations can be performed. + +### Revoking third-party signatures + +To reverse a previously issued {term}`third-party signature`, the {term}`issuer` can generate a [*certification revocation signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-certification-revocation-si) ({term}`type ID` `0x30`). The {term}`revocation` must be issued by the same {term}`key` that created the original {term}`signature` or, in deprecated practice, by a designated [Revocation Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-revocation-key). diff --git a/book/source/signing_data.md b/book/source/signing_data.md new file mode 100644 index 0000000..ca174b3 --- /dev/null +++ b/book/source/signing_data.md @@ -0,0 +1,138 @@ + + +# Signatures over data + +In OpenPGP, a *{term}`data signature`* guarantees the {term}`authenticity` and, implicitly, the integrity of certain data. Typical use cases of {term}`data signatures` include the {term}`authentication` of software packages and emails. + +"{term}`Authenticity`" in this context means that the {term}`data signature` was issued by {term}`the entity controlling the signing key material`. However, +it does not automatically signal if the expected party indeed controls the {term}`signer` {term}`certificate`. OpenPGP does offer mechanisms for *strong {term}`authentication`*, connecting {term}`certificates` to specific {term}`identities`. This verifies that the intended communication partner is indeed associated with the cryptographic {term}`identity` behind the {term}`signature`[^sign-auth]. + +[^sign-auth]: Other signing solutions, like [signify](https://flak.tedunangst.com/post/signify), focus on pure signing without strong {term}`authentication` of the {term}`signer`'s {term}`identity`. + +{term}`Data signatures` can only be issued by {term}`component keys` with the *{term}`signing`* [key flag](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-flags). + +Note that {term}`data signatures` are distinct from [](/signing_components), which are used to form and maintain {term}`certificates`, as well as to {term}`certify` {term}`identities` on {term}`certificates`. + +(data-signature-types)= +## Signature types + +{term}`OpenPGP data signatures` use one of two [signature types](signature-types): + +- [**Binary signature**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#sigtype-binary) ({term}`type ID` `0x00`): This is the standard {term}`signature type` for binary data and is typically used for files or data streams. {term}`Binary signatures` are calculated over the data without any modifications or transformations. +- [**Text signature**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-signature-of-a-canonical-te) ({term}`type ID` `0x01`): Used for textual data, such as email bodies. When calculating a {term}`text signature`, the data is first normalized by converting line endings into a canonical form (``). This approach mitigates issues caused by platform-specific text encodings. This is especially important for detached and {term}`cleartext signatures`, where the message file might undergo re-encoding between the creation and {term}`verification` of the {term}`signature`. + +{term}`Data signatures` are generated by {term}`hashing` the message content along with the {term}`metadata` in the {term}`OpenPGP signature packet`, and calculating a {term}`cryptographic signature` over that {term}`hash`. The resulting {term}`cryptographic signature` is stored in the {term}`signature packet`. + +{term}`Data signature packets` manifest in three distinct forms, which will be detailed in the subsequent section. + +(forms-of-data-signatures)= +## Forms of OpenPGP data signatures + +{term}`OpenPGP data signatures` can be applied in three distinct forms[^sign-modes-gpg]: + +- **{term}`Detached`**: The OpenPGP signature exists as a separate entity, independent of the signed data. +- **{term}`Inline`**: Both the original data and its corresponding {term}`OpenPGP signature` are encapsulated within an {term}`OpenPGP message`. +- **{term}`Cleartext signature`**: A plaintext message and its {term}`OpenPGP signature` coexist in a combined text format, preserving the readability of the original message. + +[^sign-modes-gpg]: These three forms of {term}`signature` application align with GnuPG's `--detach-sign`, `--sign`, and `--clearsign` command options. + +### Detached signatures + +A {term}`detached signature` is produced by calculating an {term}`OpenPGP signature` over the data intended for signing. The original data remains unchanged, and the {term}`OpenPGP signature` is stored as a standalone file. A {term}`detached signature` file can be distributed alongside or independent of the original data. The {term}`authenticity` and integrity of the original data file can be {term}`verified` by using the {term}`detached signature` file. + +This {term}`signature` format is especially useful for signing software releases and other files where it is imperative that the content remains unaltered during the signing process. + +(inline-signature)= +### Inline signatures + +An {term}`inline signature` joins the signed data and its corresponding {term}`data signature` into a single {term}`OpenPGP message`. + +This method is commonly used for signing or encrypting emails. Most email software capable of handling OpenPGP communications typically uses {term}`inline signatures`. + +#### Structure + +An {term}`inline-signed` {term}`OpenPGP message` consists of three segments: + +1. [**One-pass signature packets**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#one-pass-sig): These one or more {term}`packets` precede the signed data and enable {term}`signature` computation in one pass. + +2. [**Literal data packet**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#lit): This contains the original data (e.g., the body of a message), without additional interpretation or conversion. + +3. **{term}`Data signature packets`**: These contain the {term}`cryptographic signature` corresponding to the original data. + +#### Creation + +To produce an {term}`inline signature`, the {term}`signer` processes the entirety of the data by reading from an input file and writing into an output {term}`OpenPGP message` file. As the data is processed, the {term}`signer` simultaneously calculates a {term}`cryptographic signature`. This procedure results in the appending of a {term}`data signature packet` to the output {term}`OpenPGP message` file, where it can be efficiently stored. + +For efficient {term}`verification`, an application must understand how to handle the {term}`literal data` prior to its reading. This requirement is addressed by the {term}`one-pass signature packets` located at the beginning of {term}`inline-signed` messages. These {term}`packets` include essential information such as the {term}`fingerprint` of the {term}`signing key` and the {term}`hash` algorithm used for computing the {term}`signature`'s {term}`hash digest`. This setup enables the verifier to process the data correctly and efficiently. + +Strictly speaking, knowing just the hash algorithm would be sufficient to begin the verification process. However, having efficient access to the signer's fingerprint or key ID upfront allows OpenPGP software to fetch the signer's certificates before processing the entirety of the - potentially large - signed data, and . + +#### Verification + +{term}`Inline-signed` messages enable efficient {term}`verification` in *one pass*, structured as follows: + +1. **Initiation with {term}`one-pass signature packets`**: These {term}`packets` begin the {term}`verification` process. They include the {term}`signer`'s {term}`key ID`/{term}`fingerprint`, essential for identifying the appropriate {term}`public key` for signature {term}`validation`. + +2. **Processing the {term}`literal data packet`**: This step involves {term}`hashing` the literal data, preparing it for {term}`signature` {term}`verification`. + +3. **{term}`Verifying` {term}`signature packets`**: Located at the end of the message, these {term}`packets` are checked against the previously calculated {term}`hash digest`. + +Important to note, the {term}`signer`'s {term}`public key`, critical for the final {term}`verification` step, is not embedded in the message. Verifiers must acquire this {term}`key` externally (e.g., from a {term}`key server`) to authenticate the {term}`signature` successfully. + +(cleartext-signature)= +### Cleartext signatures + +The *{term}`Cleartext Signature Framework`* (CSF) in OpenPGP accomplishes two primary objectives: + +- maintaining the message in a human-readable cleartext format, accessible without OpenPGP-specific software +- incorporating an {term}`OpenPGP signature` for {term}`authentication` by users with OpenPGP-compatible software + +#### Example + +The following is a detailed example of a {numref}`cleartext` signature: + +```text +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +hello world +-----BEGIN PGP SIGNATURE----- + +wpgGARsKAAAAKQWCZT0vBCIhBtB7JOyRoU3SQKwtU+bIqeBUlJpBIi6nOFdu0Zyu +o9yZAAAAANqgIHAzoRTzu/7Zuxc8Izf4r3/qSCmBfDqWzTXqmVtsSBSHACka3qbN +eehqu8H6S0UK8V7yHbpVhExu9Hu72jWEzU/B0h9MR5gDhJPoWurx8YfyXBDsRS4y +r13/eqMN8kfCDw== +=Ks9w +-----END PGP SIGNATURE----- +``` + +This {term}`signature` consists of two parts: a message ("hello world") and an ASCII-armored {term}`OpenPGP signature`. The message is immediately comprehensible to a human reader, while the {term}`signature` block allows for the message's {term}`authenticity` {term}`verification` via OpenPGP software. + +#### Use case + +{term}`Cleartext signatures` combine the advantages of both {term}`detached` and {term}`inline signatures`: + +- **Self-contained format**: {term}`Cleartext signatures` enable the message and its {term}`signature` to be stored as a single file. + +- **Human readability**: The message within a {term}`cleartext signature` remains accessible in a plain text format. This eliminates the need for specialized software to read the message content. + +These features are particularly beneficial in scenarios where signed messages are managed semi-manually and where existing system infrastructure offers limited or no native support for OpenPGP in the workflow[^arch-certifications]. + +[^arch-certifications]: An illustrative example is the workflow adopted by Arch Linux to {term}`certify` {term}`User IDs` of new packagers. This process relies on [cleartext signed statements from existing packagers](https://gitlab.archlinux.org/archlinux/archlinux-keyring/-/blob/master/.gitlab/issue_templates/New%20Packager%20Key.md?ref_type=heads&plain=1#L33-46). These signed statements are stored as attachments in an issue tracking system for later inspection. The advantage of this approach lies in the convenience of having the message and signature in a single file, which simplifies manual handling. Based on the vouches in these {term}`cleartext signed` messages and an [email confirmation from the new packager](https://gitlab.archlinux.org/archlinux/archlinux-keyring/-/wikis/workflows/verify-a-packager-key), the main key operators can issue {term}`OpenPGP third-party certifications`. + +#### Text transformations for cleartext signatures + +The {term}`cleartext signature framework` includes specific text normalization procedures to ensure the integrity and clarity of the message: + +- **Escaping dashes**: The framework implements a method of [dash-escaped text](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-dash-escaped-text) within the message. Dash-escaping ensures that the parser correctly distinguishes between the armor headers, which are part of the {term}`signature`'s structure, and any lines in the message that happen to start with a dash. + +- **Normalization of line endings**: Consistent with the approach for any other [text signature](data-signature-types), a {term}`cleartext signature` is calculated on the text with normalized line endings (``). This ensures that the {term}`signature` remains valid regardless of the text format of the receiving {term}`implementation`. + +#### Pitfalls + +Despite their widespread adoption, {term}`cleartext signatures` have their limitations and are sometimes viewed as a "legacy method"[^csf-gnupg]. The {term}`RFC` details the [pitfalls of cleartext signatures](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-issues-with-the-cleartext-s), such as incompatibility with semantically meaningful whitespace, challenges with large messages, and security vulnerabilities related to misleading Hash header manipulations. Given these issues, safer alternatives like {term}`inline` and {term}`detached signature` forms are advised. + +[^csf-gnupg]: https://lists.gnupg.org/pipermail/gnupg-devel/2023-November/035428.html diff --git a/book/source/verification.md b/book/source/verification.md new file mode 100644 index 0000000..4c68199 --- /dev/null +++ b/book/source/verification.md @@ -0,0 +1,117 @@ + + +# Signature verification + +Signature verification in the OpenPGP protocol is a complex process. +Many factors influence the validity of a signature. + +Firstly, its expiration time: A signature can be valid at one point in time and expired a second later. + +Signatures can be invalid due to the absence or presence of other signatures (e.g., revocations). +Some signatures can be verified standalone, while others require the verification of a chain-like structure of signatures, mostly within the issuer's certificate. + +## When are signatures valid? + +As a necessary condition, a valid signature must be [cryptographically correct](signature-verify). This means that both the signature and its signed input data must be intact. + +However, there is a difference between signature *correctness* and *validity*: + +A signature may be cryptographically correct, but still not qualify as a *valid* signature. +Put mathematically, the set of valid signatures is a subset of the set of correct signatures. + +The validity of a correct signature is additionally constrained by a number of conditions: + +* **Well-formedness**: Signature packets need to be well-formed. This means that they must contain suitable signature metadata (this includes: the required signature subpackets must be present in the proper subpacket area). The signature metadata must not contain unknown critical subpackets or unknown critical notations[^unknown-critical]. Some implementations additionally apply a policy that constrains accepted hash algorithms, cryptographic algorithms, and key strengths. +* **Temporal validity**: Most signatures have a limited validity period, constrained by the signature creation- and expiration time. +* **Qualification**: Furthermore, some signatures need to be *qualified* by other valid signatures in order to be considered valid. This is especially the case with signatures created by dedicated signing subkeys, where, in addition to the signature itself, the subkeys binding signature(s) must be verified. +* **Revocation**: Lastly, signatures can be invalidated by revocations. + +[^unknown-critical]: Note that this implies that a signature might be considered valid by one implementation and be rejected by another, based on the set of subpackets and notations each implementation is aware of. + +## Well-formedness of signatures + +There are a number of criteria that a signature must fulfill to be considered well-formed: + +- Each signature MUST have a signature creation time subpacket in its hashed subpacket area. A signature with only an unhashed creation time - or none at all - is not well-formed. +- The signature cannot be older than the component key that issued it. +- Analogously, a signature with a creation time in the future needs to be rejected as well. +- A well-formed signature needs to carry an Issuer Fingerprint subpacket, or an Issuer KeyID subpacket. It is generally recommended to place Issuer subpackets in the hashed area of the signature, but a receiving implementation may also accept signatures which only contain unhashed copies of these subpackets. +- A signature disqualifies as well-formed if it contains subpackets which are marked as critical, but unknown to the receiving implementation. Unknown subpackets which are not marked as critical do not have an effect on whether the signature is well-formed. +- The same applies to notations. Unknown notations that are marked as critical render the signature malformed. + +(temporal-validity)= +## Temporal validity + +A signature is valid only for a constrained period of time: + +- The creation time of the signature acts as a lower bound for the validity. A signature only becomes valid at its creation time. Hard revocation signatures are an exception: They are by definition valid at any point in time, and have no lower temporal bound. +- If present, the signature's expiration time acts as a natural upper bound for its validity. + +When checking a signature for validity, a reference time is used. The validity of the signature is evaluated at that reference time. + +The reference time can be: + +- the current time during validation, or +- another point in time that is significant to the signature that is validated. For example, when checking the signature of an email, the reference time might be the signature creation time, or the time of receipt of the email. + +For the signature to qualify as valid, it needs to be in effect. In other words, the reference time must fall into the period between signature creation and signature expiration. + +The same reference time must be used when verifying required qualifying signatures, if any. + +## Self-qualifying and non-self-qualifying signatures + +Some signatures can be verified on their own, while others require the verification of additional signatures on the issuer certificate. We will call the former category *self-qualifying* signatures. + +Typically, self-qualifying signatures are self-signatures, meaning signatures issued by an OpenPGP primary key for the components in its certificate. + +Examples for self-qualifying signatures are: + +- direct key self-signatures (`0x1F`), +- User ID self-certifications (`0x10`-`0x13`), +- key-revocation self-signatures (`0x20`), +- certification revocation self-signatures (`0x30`) or +- self-signatures used to bind or revoke subkeys (`0x18`, `0x19`, `0x28`). + +Examples for signatures which are not self-qualifying are: + +- data signatures (`0x00`, `0x01`) and +- signatures issued over third-party certificates, such as: + - third-party direct key signatures (`0x1F`), + - third-party key-revocations (`0x20`), + - third-party certification (`0x10`-`0x13`), or + - third-party certification revocation signatures (`0x30`). + +## Signature qualification + +To verify non-self-qualifying signatures, it is necessary to look at more than just the signature itself. + +This is required because the issuing component key needs to be qualified to create such a signature (e.g., because a specific capability key flag is required). The qualification typically emerges via a self-signature on the key itself. + +In short, a chain of valid signatures from the signature itself to the primary key of the issuer certificate needs to be established. + +For example, a subkey may issue a data signature over an email body only if that subkey is validly bound to the issuer's certificate via a subkey binding signature. That binding signature needs to contain a *key flags* subpacket that marks the subkey as *signing* capable. +Similarly, certification signatures over third-party certificates require the issuer key to carry a valid self-signature with the *certification* key flag. + +Self-qualifying signatures have no such limitations. + +For example, a certificate consisting only of a primary key and a single key-revocation self-signature contains everything needed to verify the revocation, as key-revocation self-signatures are self-qualifying. +This construct is referred to as a [revocation certificate](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-openpgp-v6-revocation-certi). + +On the other hand, to verify a data signature over a text document, an implementation needs to verify not only the data signature itself, but also the binding signature (and back-signature) of the signing subkey which qualifies the signing subkey. + +```{figure} img/mermaid/09-sigtree.png +:name: fig-signature-verification-signature-tree +:alt: Depicts a diagrammatic representation of a certificate and a data signature. Arrows between the primary key and other components of the certificate show, how signatures bind the certificate together. In this example, they form a tree of signatures, which all need to be verified in order for the data signature to be valid. + +Tree of signatures that qualify a data signature +``` + +## Revocations + +A signature can be *disqualified* by the presence of a revocation signature. + +Revocations can be limited in scope, e.g., a subkey-revocation signature only revokes a single subkey. +Moreover, revocations can also be constrained to a certain validity period by including a soft revocation reason and expiration time in the revocation signature. diff --git a/book/source/versions.md b/book/source/versions.md new file mode 100644 index 0000000..e78b80b --- /dev/null +++ b/book/source/versions.md @@ -0,0 +1,13 @@ + + +# OpenPGP versions + +## Differences between OpenPGP versions + +```{note} + +This section is still about to be written. +``` diff --git a/book/source/zoom/certificates.md b/book/source/zoom/certificates.md new file mode 100644 index 0000000..4be810e --- /dev/null +++ b/book/source/zoom/certificates.md @@ -0,0 +1,785 @@ + + +# 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 + +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. + +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/certificate using the following command: + +```text +$ sq key extract-cert alice.priv > alice.pub +``` + +(zoom-split-alice)= +### Splitting the OpenPGP certificate into packets + +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 extracted from the original full certificate in `alice.pub`: + +```text +alice.pub-0--PublicKey +alice.pub-1--Signature +alice.pub-2--UserID +alice.pub-3--Signature +alice.pub-4--PublicSubkey +alice.pub-5--Signature +alice.pub-6--PublicSubkey +alice.pub-7--Signature +alice.pub-8--PublicSubkey +alice.pub-9--Signature +``` + + +```{figure} ../plain_svg/certificate_packet_list.svg +:name: fig-certificate-packet-list +:alt: Depicts a box with white background and the title "Certificate packet list". Inside, a list of several boxes on white background and varying frame colors represent a list of OpenPGP packets from top to bottom. The first box, with green frame, represents the "Public-Key packet", and includes the green public key symbol. The second box, with yellow frame, represents a "Signature packet" ("Direct Key Signature") and includes the green cryptographic signature symbol. The third box, with black frame, represents a "User ID packet", and includes the black User ID symbol. The fourth box, with yellow frame, represents a "Signature packet" ("Certifying self-signature for User ID"), and includes the green cryptographic signature symbol. The fifth box, with green frame, represents a "Public-Subkey packet" and includes the green public key symbol. The sixth box, with yellow frame, represents a "Signature packet" ("Subkey binding signature") and includes the green cryptographic signature symbol. The seventh box, with green frame, represents a "Public-Subkey packet" and includes the green public key symbol. The eighth box, with yellow frame, represents a "Signature packet" ("Subkey binding signature") and includes the green cryptographic signature symbol. The ninth box, with green frame, represents a "Public-Subkey packet" and includes the green public key symbol. The tenth box, with yellow frame, represents a "Signature packet" ("Subkey binding signature") and includes the green cryptographic signature symbol. + +Overview of the packets in Alice's OpenPGP certificate +``` + +This process allows us to focus on the specific packets within Alice's OpenPGP 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-12.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-12.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 explore in the subsequent sections: + +```{figure} ../plain_svg/Minimal_OpenPGP_certificate.svg +:name: fig-public-certificate-minimal +:alt: TODO + +A minimal OpenPGP certificate, visualized +``` + +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 appears as follows: + +```text +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xioGZRbqphsAAAAgUyTpQ6+rFfdu1bUSmHlpzRtdEGXr50Liq0f0hrOuZT7CtgYf +GwoAAAA9BYJlFuqmBYkFpI+9AwsJBwMVCggCmwECHgEiIQaqoYy7JUaFxYNYMgVj +/Te2fzMA+fsOxFc3jNKfECaYswAAAAoJEKqhjLslRoXFZ0cgouNjgeNr0E9W18g4 +gAIl6FM5SWuQxg12j0S07ExCOI5NPRDCrSnAV85mAXOzeIGeiVLPQ40oEal3CX/L ++BXIoY2sIEQrLd4TAEEy0BA8aQZTPEmMdiOCM1QB+V+BQZAO +=5nyq +-----END PGP PUBLIC KEY BLOCK----- +``` + +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 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. + +(zoom-public-key)= +### Public-Key packet + +The output begins with a (primary) [Public-Key packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-packet-formats): + +```text +Public-Key Packet, new CTB, 2 header bytes + 42 bytes + Version: 6 + Creation time: 2023-09-29 15:17:58 UTC + Pk algo: Ed25519 + Pk size: 256 bits + Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3 + KeyID: AAA18CBB254685C5 + + 00000000 c6 CTB + 00000001 2a length + 00000002 06 version + 00000003 65 16 ea a6 creation_time + 00000007 1b pk_algo + 00000008 00 00 00 20 public_len + 0000000c 53 24 e9 43 ed25519_public + 00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65 + 00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e +``` + +The Public-Key packet consists primarily of the cryptographic key data. Let's look at the packet field by field: + +**OpenPGP packet syntax** + +The first fields of a packet are governed by the general [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-syntax): + +- `CTB: 0xc6`[^CTB]: This is the [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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-12.html#name-packet-types). + +- `length: 0x2a`: This indicates the remaining length of this packet. + +**Public-Key packet syntax** + +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-12.html#name-key-material-packets). + +- `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-12.html#name-version-6-public-keys). + +- `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-12.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-12.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-12.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 ({term}`Cipher Type Byte`) to refer to the [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers). + +Note that the *Public-Key packet* contains only the public part of the key. + +```{figure} ../plain_svg/public-key_packet.svg +:name: fig-public-key-packet +:alt: Depicts a box with white background and title "Public-Key packet". In the center a box with white background and green frame is shown. Inside it several items are listed, separated by green dotted horizontal lines. The first three are "Version", "Creation Time", "Public-Key Algorithm" written in black. The last one is written in green and reads "Public Key Material" and has the green public key symbol at its right side. + +Structure of a Public-Key packet. +``` + +(zoom-dks)= +### Direct Key Signature + +The next packet in the certificate is a [*Direct Key Signature*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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 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 + Version: 6 + Type: DirectKey + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-09-29 15:17:58 UTC (critical) + Key expiration time: P1095DT62781S (critical) + Symmetric algo preferences: AES256, AES128 + Hash preferences: SHA512, SHA256 + Key flags: C (critical) + Features: MDC + Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3 + Unhashed area: + Issuer: AAA18CBB254685C5 + Digest prefix: 6747 + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 b6 length + 00000002 06 version + 00000003 1f type + 00000004 1b pk_algo + 00000005 0a hash_algo + 00000006 00 00 00 3d hashed_area_len + 0000000a 05 subpacket length + 0000000b 82 subpacket tag + 0000000c 65 16 ea a6 sig creation time + 00000010 05 subpacket length + 00000011 89 subpacket tag + 00000012 05 a4 8f bd key expiry time + 00000016 03 subpacket length + 00000017 0b subpacket tag + 00000018 09 07 pref sym algos + 0000001a 03 subpacket length + 0000001b 15 subpacket tag + 0000001c 0a 08 pref hash algos + 0000001e 02 subpacket length + 0000001f 9b subpacket tag + 00000020 01 key flags + 00000021 02 subpacket length + 00000022 1e subpacket tag + 00000023 01 features + 00000024 22 subpacket length + 00000025 21 subpacket tag + 00000026 06 version + 00000027 aa a1 8c bb 25 46 85 c5 83 issuer fp + 00000030 58 32 05 63 fd 37 b6 7f 33 00 f9 fb 0e c4 57 37 + 00000040 8c d2 9f 10 26 98 b3 + 00000047 00 00 00 0a unhashed_area_len + 0000004b 09 subpacket length + 0000004c 10 subpacket tag + 0000004d aa a1 8c issuer + 00000050 bb 25 46 85 c5 + 00000055 67 digest_prefix1 + 00000056 47 digest_prefix2 + 00000057 20 salt_len + 00000058 a2 e3 63 81 e3 6b d0 4f salt + 00000060 56 d7 c8 38 80 02 25 e8 53 39 49 6b 90 c6 0d 76 + 00000070 8f 44 b4 ec 4c 42 38 8e + 00000078 4d 3d 10 c2 ad 29 c0 57 ed25519_sig + 00000080 ce 66 01 73 b3 78 81 9e 89 52 cf 43 8d 28 11 a9 + 00000090 77 09 7f cb f8 15 c8 a1 8d ac 20 44 2b 2d de 13 + 000000a0 00 41 32 d0 10 3c 69 06 53 3c 49 8c 76 23 82 33 + 000000b0 54 01 f9 5f 81 41 90 0e +``` + +Below is a field-by-field examination of the packet: + +**OpenPGP packet syntax** + +The first fields of a packet are governed by the general [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-syntax): + +- `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. + +- `length: 0xb6`: This field shows the remaining length of this packet. + +**Signature packet syntax** + +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-12.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-12.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-12.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-12.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-12.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-12.html#section-5.2.3.7-7) + +```{note} +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. +``` + +The subpacket details are as follows: + +- [**Signature Creation Time**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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-12.html#name-time-fields). + +- [**Key Expiration Time**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#key-expiration-subpacket) + - Type: `9` + - Critical: `Yes` + - Value: `0x05a48fbd` + - Notes: 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-12.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* + +- [**Preferred Hash Algorithms**](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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-12.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-12.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-12.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-12.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. + +This next section shows the remaining fields of this signature packet, which relate to the cryptographic digital signature: + +- `digest_prefix: 0x6747`: the left 16 bits of the signed hash digest + +- `salt_len, salt`: a random [salt value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-advantages-of-salted-signat) with size [matching the hash algorithm](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#hash-algorithms-registry)) + +- `ed25519_sig`: [algorithm-specific](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.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-12.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} ../plain_svg/direct_key_signature_packet.svg +:name: fig-direct-key-signature-packet +:alt: Depicts a box with white background, title "Signature packet" and subtitle "Direct Key Signature (type ID 0x1F)". In the center a box with white background and yellow frame is shown. Inside it several items are listed, separated by yellow dotted horizontal lines. The first three are "Version", "Public-Key Algorithm" and "Hash Algorithm". The fourth item is called "Hashed area" and confines further sub-items by a light-yellow frame on the top and left side. The sub-items are "Signature Creation Time", "Key Expiration Time", "Preferred Symmetric Ciphers for v1 SEIPD", "Preferred Hash Algorithms", "Key Flags", "Features" and "Issuer Fingerprint". The fifth item is named "Unhashed area" and again introduces an area for sub-items, this time using a light-gray border on the top and left side. The unhashed area has no sub-items though. The last item is called "Cryptographic Signature", with the subtitle "by the primary key over primary key, subkey and signature metadata" and includes the green cryptographic signature symbol on the right side. + +Structure of a direct key signature packet. +``` + +(zoom-subkey-enc)= +## Encryption subkey + +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, implicitly, to the full OpenPGP certificate. + +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 as shown below: + +```text +$ sq packet dump --hex alice.pub +``` + +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](zoom-split-alice)). Finding a particular packet in that list can take a bit of focus and practice though. + +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 + +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 +Public-Subkey Packet, new CTB, 2 header bytes + 42 bytes + Version: 6 + Creation time: 2023-09-29 15:17:58 UTC + Pk algo: X25519 + Pk size: 256 bits + Fingerprint: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94 + KeyID: C0A58384A438E5A1 + + 00000000 ce CTB + 00000001 2a length + 00000002 06 version + 00000003 65 16 ea a6 creation_time + 00000007 19 pk_algo + 00000008 00 00 00 20 public_len + 0000000c d1 ae 87 d7 x25519_public + 00000010 cc 42 af 99 34 c5 c2 5c ca fa b7 4a c8 43 fc 86 + 00000020 35 2a 46 01 f3 cc 00 f5 4a 09 3e 3f +``` + +Notice that the structure of this *Public-Subkey packet* mirrors the primary key's [*Public-Key packet*](zoom-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-12.html#name-public-subkey-packet-type-i)). + +- 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-12.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 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 is called a *subkey binding signature*, because it "binds" or connects the subkey to the rest of the key. + +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 +Signature Packet, new CTB, 2 header bytes + 171 bytes + Version: 6 + Type: SubkeyBinding + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-09-29 15:17:58 UTC (critical) + Key expiration time: P1095DT62781S (critical) + Key flags: EtEr (critical) + Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3 + Unhashed area: + Issuer: AAA18CBB254685C5 + Digest prefix: 2289 + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 ab length + 00000002 06 version + 00000003 18 type + 00000004 1b pk_algo + 00000005 0a hash_algo + 00000006 00 00 00 32 hashed_area_len + 0000000a 05 subpacket length + 0000000b 82 subpacket tag + 0000000c 65 16 ea a6 sig creation time + 00000010 05 subpacket length + 00000011 89 subpacket tag + 00000012 05 a4 8f bd key expiry time + 00000016 02 subpacket length + 00000017 9b subpacket tag + 00000018 0c key flags + 00000019 22 subpacket length + 0000001a 21 subpacket tag + 0000001b 06 version + 0000001c aa a1 8c bb issuer fp + 00000020 25 46 85 c5 83 58 32 05 63 fd 37 b6 7f 33 00 f9 + 00000030 fb 0e c4 57 37 8c d2 9f 10 26 98 b3 + 0000003c 00 00 00 0a unhashed_area_len + 00000040 09 subpacket length + 00000041 10 subpacket tag + 00000042 aa a1 8c bb 25 46 85 c5 issuer + 0000004a 22 digest_prefix1 + 0000004b 89 digest_prefix2 + 0000004c 20 salt_len + 0000004d 0b 0c 89 salt + 00000050 b5 ab 15 e3 7f e4 4d b9 a7 ef 71 48 14 3b ab 26 + 00000060 5f 34 7f 6d 48 2e 9f 78 48 58 6d 9a fb + 0000006d 6d b2 db ed25519_sig + 00000070 2f 97 8e c8 12 fc 57 7f 85 aa d1 59 bc 80 40 0b + 00000080 be 2e f0 e1 23 2d bf 4b 71 7e d0 e4 c0 36 e4 d2 + 00000090 cf b2 9f b4 a8 4f 3e 2a 21 89 74 c2 33 55 af ac + 000000a0 41 36 1b 2b 60 09 f2 d9 19 f4 41 12 0b +``` + +The analysis of this packet dump will be less extensive, given that its structure mirrors the *Direct Key Signature* explored above. + +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-12.html#name-subkey-binding-signature-ty)). + +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` + +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 digest. In this case, the hash digest is derived from the following data: + +- 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-12.html#name-computing-signatures) in the RFC for details. + +## Signing subkey + +```{note} + +This section is still about to be written. +``` + +```text +$ sq packet dump --hex alice.pub-6--PublicSubkey +Public-Subkey Packet, new CTB, 2 header bytes + 42 bytes + Version: 6 + Creation time: 2023-09-29 15:17:58 UTC + Pk algo: Ed25519 + Pk size: 256 bits + Fingerprint: D07B24EC91A14DD240AC2D53E6C8A9E054949A41222EA738576ED19CAEA3DC99 + KeyID: D07B24EC91A14DD2 + + 00000000 ce CTB + 00000001 2a length + 00000002 06 version + 00000003 65 16 ea a6 creation_time + 00000007 1b pk_algo + 00000008 00 00 00 20 public_len + 0000000c 33 8c d4 f5 ed25519_public + 00000010 1a 73 39 ef ce d6 0f 21 8d a0 58 a2 3c 3d 44 a8 + 00000020 59 e9 13 1f 12 9c 6f 19 d0 3d 40 a0 +``` + +```text +$ sq packet dump --hex alice.pub-7--Signature +Signature Packet, new CTB, 3 header bytes + 325 bytes + Version: 6 + Type: SubkeyBinding + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-09-29 15:17:58 UTC (critical) + Key expiration time: P1095DT62781S (critical) + Key flags: S (critical) + Embedded signature: (critical) + Signature Packet + Version: 6 + Type: PrimaryKeyBinding + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-09-29 15:17:58 UTC (critical) + Issuer Fingerprint: D07B24EC91A14DD240AC2D53E6C8A9E054949A41222EA738576ED19CAEA3DC99 + Digest prefix: 5365 + Level: 0 (signature over data) + + Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3 + Unhashed area: + Issuer: AAA18CBB254685C5 + Digest prefix: 841C + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 c0 85 length + 00000003 06 version + 00000004 18 type + 00000005 1b pk_algo + 00000006 0a hash_algo + 00000007 00 00 00 cc hashed_area_len + 0000000b 05 subpacket length + 0000000c 82 subpacket tag + 0000000d 65 16 ea sig creation time + 00000010 a6 + 00000011 05 subpacket length + 00000012 89 subpacket tag + 00000013 05 a4 8f bd key expiry time + 00000017 02 subpacket length + 00000018 9b subpacket tag + 00000019 02 key flags + 0000001a 99 subpacket length + 0000001b a0 subpacket tag + 0000001c 06 19 1b 0a embedded sig + 00000020 00 00 00 29 05 82 65 16 ea a6 22 21 06 d0 7b 24 + 00000030 ec 91 a1 4d d2 40 ac 2d 53 e6 c8 a9 e0 54 94 9a + 00000040 41 22 2e a7 38 57 6e d1 9c ae a3 dc 99 00 00 00 + 00000050 00 53 65 20 42 03 ad 0c db fc b5 9a 98 a6 15 27 + 00000060 e4 11 5e f5 f2 a0 3d bc ed 8d 94 27 41 09 f6 3c + 00000070 4b f8 8a e5 af 73 e1 7d 54 07 40 3f f3 29 34 c2 + 00000080 e7 60 56 a5 e1 43 cb 08 ba 66 fe 8b 26 ce e7 cb + 00000090 a5 3a 46 bb a5 c8 5d e4 6a de ae 49 e1 3e 07 bf + 000000a0 c4 9e 98 14 2f 3e c5 f7 01 3e 3e 4f f6 18 2a ac + 000000b0 bd ed 52 0c + 000000b4 22 subpacket length + 000000b5 21 subpacket tag + 000000b6 06 version + 000000b7 aa a1 8c bb 25 46 85 c5 83 issuer fp + 000000c0 58 32 05 63 fd 37 b6 7f 33 00 f9 fb 0e c4 57 37 + 000000d0 8c d2 9f 10 26 98 b3 + 000000d7 00 00 00 0a unhashed_area_len + 000000db 09 subpacket length + 000000dc 10 subpacket tag + 000000dd aa a1 8c issuer + 000000e0 bb 25 46 85 c5 + 000000e5 84 digest_prefix1 + 000000e6 1c digest_prefix2 + 000000e7 20 salt_len + 000000e8 23 3d b2 49 f3 02 4b 08 salt + 000000f0 93 af ba 08 89 f0 e0 91 0f ab 22 26 aa b3 56 57 + 00000100 30 ea 95 29 06 60 6f 00 + 00000108 be 44 a1 95 38 a9 6b 3a ed25519_sig + 00000110 3e 51 f0 55 09 b1 e2 91 a9 17 86 fa f5 1e 3f d0 + 00000120 28 46 3c ce 6e 88 14 37 32 ec 3d fa c6 01 ca e5 + 00000130 a9 4b b7 63 94 c3 0d 92 ab dc fa 23 50 71 60 31 + 00000140 a6 73 c8 33 5a 9c d9 0a +``` + +(zoom-user-id)= +## Adding an identity component + +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. Typically, a User ID is a string combining a name and an email address. + +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-12.html#uid), 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-12.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 is associated with an OpenPGP certificate: + +```text +$ sq packet dump --hex alice.pub-2--UserID +User ID Packet, new CTB, 2 header bytes + 19 bytes + Value: + + 00000000 cd CTB + 00000001 13 length + 00000002 3c 61 6c 69 63 65 40 65 78 61 6d 70 6c 65 value + 00000010 2e 6f 72 67 3e +``` + +- `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-12.html#uid). + +- `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 + +Similar to [linking a subkey](zoom-subkey-enc) 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, 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 +Signature Packet, new CTB, 2 header bytes + 185 bytes + Version: 6 + Type: PositiveCertification + Pk algo: Ed25519 + Hash algo: SHA512 + Hashed area: + Signature creation time: 2023-09-29 15:17:58 UTC (critical) + Key expiration time: P1095DT62781S (critical) + Symmetric algo preferences: AES256, AES128 + Hash preferences: SHA512, SHA256 + Primary User ID: true (critical) + Key flags: C (critical) + Features: MDC + Issuer Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3 + Unhashed area: + Issuer: AAA18CBB254685C5 + Digest prefix: DBB8 + Level: 0 (signature over data) + + 00000000 c2 CTB + 00000001 b9 length + 00000002 06 version + 00000003 13 type + 00000004 1b pk_algo + 00000005 0a hash_algo + 00000006 00 00 00 40 hashed_area_len + 0000000a 05 subpacket length + 0000000b 82 subpacket tag + 0000000c 65 16 ea a6 sig creation time + 00000010 05 subpacket length + 00000011 89 subpacket tag + 00000012 05 a4 8f bd key expiry time + 00000016 03 subpacket length + 00000017 0b subpacket tag + 00000018 09 07 pref sym algos + 0000001a 03 subpacket length + 0000001b 15 subpacket tag + 0000001c 0a 08 pref hash algos + 0000001e 02 subpacket length + 0000001f 99 subpacket tag + 00000020 01 primary user id + 00000021 02 subpacket length + 00000022 9b subpacket tag + 00000023 01 key flags + 00000024 02 subpacket length + 00000025 1e subpacket tag + 00000026 01 features + 00000027 22 subpacket length + 00000028 21 subpacket tag + 00000029 06 version + 0000002a aa a1 8c bb 25 46 issuer fp + 00000030 85 c5 83 58 32 05 63 fd 37 b6 7f 33 00 f9 fb 0e + 00000040 c4 57 37 8c d2 9f 10 26 98 b3 + 0000004a 00 00 00 0a unhashed_area_len + 0000004e 09 subpacket length + 0000004f 10 subpacket tag + 00000050 aa a1 8c bb 25 46 85 c5 issuer + 00000058 db digest_prefix1 + 00000059 b8 digest_prefix2 + 0000005a 20 salt_len + 0000005b 8a 2d 6f da 67 salt + 00000060 35 bc 5d 04 77 b4 9d 67 a8 6e c5 d6 88 53 5f e2 + 00000070 ef f9 66 08 bf c2 e0 db c0 56 0d + 0000007b eb d4 2c a5 19 ed25519_sig + 00000080 01 0f ba 26 d0 82 a2 cf 5c eb 7a a9 72 d9 f3 b2 + 00000090 66 07 8b b2 ba 3d b7 89 e4 76 04 6e 35 24 2b 27 + 000000a0 29 83 be 91 9c 78 6a cc b4 d5 69 47 76 2c 29 d6 + 000000b0 54 bf 43 19 04 ff 53 98 c0 d5 0b +``` + + +Because this packet structure closely mirrors the [Direct Key Signature](zoom-dks) discussed above, we will cover this succinctly. + +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-12.html#name-signature-types)). + +The designated public key algorithm and hash function for this signature are Ed25519 and SHA512, respectively. + +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**) +- Symmetric algo preferences: `AES256, AES128` +- Hash preferences: `SHA512, SHA256` +- Primary User ID: `true` (**critical**) +- Key flags: `C` (**critical**) +- Features: `MDC` +- Issuer fingerprint: `AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3` + +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} +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-12.html#name-notes-on-self-signatures), with changes between version 6 and version 4. +```` + +This section is followed, again, by the (informational) unhashed subpacket area. + +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 derived from the following data: + +- 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-12.html#name-computing-signatures) in the RFC for details. + +## Certifications (Third Party Signatures) + +```{note} + +This section is still about to be written. +``` + +## Revocations + +```{note} + +This section is still about to be written. +``` diff --git a/book/source/zoom/encryption.md b/book/source/zoom/encryption.md new file mode 100644 index 0000000..7a9feff --- /dev/null +++ b/book/source/zoom/encryption.md @@ -0,0 +1,113 @@ + + +# Zooming in: Packet structure of encrypted data + +## SEIPD v2 + +### Encrypt + +We encrypt a short message to Alice, using a public certificate version of {ref}`alice-priv`: + +```text +$ echo "hello world" | sq encrypt --recipient-file alice.pub +``` + +This produces an ASCII armored encrypted message: + +```{literalinclude} ../examples/ascii_armored_encrypted_message.asc +:language: text +``` + +### Inspect the packet dump of the encrypted message + +Inspecting the packets of this message, we see: + +```text +$ sq packet dump --hex enc.pgp +Public-Key Encrypted Session Key Packet, new CTB, 2 header bytes + 93 bytes + Version: 6 + Recipient: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94 + Pk algo: X25519 + + 00000000 c1 CTB + 00000001 5d length + 00000002 06 version + 00000003 21 recipient_len + 00000004 06 recipient_version + 00000005 c0 a5 83 84 a4 38 e5 a1 4f 73 71 recipient + 00000010 24 26 a4 d4 5d ba ee f4 a3 9e 6b 30 b0 9d 55 13 + 00000020 f9 78 ac ca 94 + 00000025 19 pk_algo + 00000026 31 61 a4 33 ba eb 03 ef ca 23 x25519_e + 00000030 01 d8 86 c1 0f 0c 23 cb 12 01 70 15 e0 01 0c 28 + 00000040 87 1b 20 da a1 20 + 00000046 18 x25519_esk_len + 00000047 12 9b 91 15 f6 1f 98 97 f5 x25519_esk + 00000050 d5 dd f1 19 d4 93 9a 06 7a ed b2 8d 99 01 2e + +Sym. Encrypted and Integrity Protected Data Packet, new CTB, 2 header bytes + 114 bytes + Version: 2 + Symmetric algo: AES-128 + AEAD algo: EAX + Chunk size: 4096 + Salt: 9673F229E1386AD0464367096945493F4D42FE4D6129B06750B3C89F0F214093 + No session key supplied + + 00000000 d2 CTB + 00000001 72 length + 00000002 02 version + 00000003 07 sym_algo + 00000004 01 aead_algo + 00000005 06 chunk_size + 00000006 96 73 f2 29 e1 38 6a d0 46 43 salt + 00000010 67 09 69 45 49 3f 4d 42 fe 4d 61 29 b0 67 50 b3 + 00000020 c8 9f 0f 21 40 93 + 00000026 bb 77 fb 75 ef bc ba f9 75 48 .w.u....uH + 00000030 37 f8 eb 7e b0 44 a4 09 28 e1 ad 99 39 d0 72 23 7..~.D..(...9.r# + 00000040 c2 30 55 67 a6 35 e7 dc 9f 68 ea ad b4 c4 fa 71 .0Ug.5...h.....q + 00000050 7a 96 6b 12 22 b2 13 da 27 e3 91 d6 ad 9b 65 2d z.k."...'.....e- + 00000060 4d da 31 5b 69 13 8e 71 b0 12 2b a0 15 ce a0 96 M.1[i..q..+..... + 00000070 9d ea a4 20 ... +``` + +### Decrypt + +```text +$ sq decrypt --dump-session-key --recipient-file alice.sec enc.pgp +Session key: 8DDA27B9B000BD84D0A39DFF66780111 +Encrypted using AES-128 +Compressed using ZIP +hello world +``` + +Inspecting the packets inside the SEIPD container: + +```text +$ sq decrypt --dump --recipient-file alice.sec enc.pgp +Public-Key Encrypted Session Key Packet, new CTB, 93 bytes + Version: 6 + Recipient: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94 + Pk algo: X25519 + +Encrypted using AES-128 +Compressed using ZIP +hello world +Sym. Encrypted and Integrity Protected Data Packet, new CTB, 114 bytes +│ Version: 2 +│ Symmetric algo: AES-128 +│ AEAD algo: EAX +│ Chunk size: 4096 +│ Salt: 9673F229E1386AD0464367096945493F4D42FE4D6129B06750B3C89F0F214093 +│ +└── Compressed Data Packet, new CTB, 44 bytes + │ Algorithm: ZIP + │ + ├── Literal Data Packet, new CTB, 18 bytes + │ Format: Binary data + │ + └── Padding Packet, new CTB, 14 bytes + Unknown variant +``` diff --git a/book/source/zoom/private_keys.md b/book/source/zoom/private_keys.md new file mode 100644 index 0000000..5be67e1 --- /dev/null +++ b/book/source/zoom/private_keys.md @@ -0,0 +1,192 @@ + + +# Zooming in: Packet structure of private key material + +## A look at Alice's (unencrypted) private key packets + +Let's take a look at the key material packets of [Alice's key](alice-priv). + +To inspect the internal structure of Alice's key, we run the Sequoia-PGP tool `sq` (using the `packet dump` subcommand). The output of `sq` is one big block of text. To discuss the relevant content, we'll only show the output for the packets that contain key data, here: + +```text +$ 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-12.html#name-secret-key-packet-formats). + +This is the structure of the Secret-Key packet we will now look at. + +```{figure} ../plain_svg/secret-key_packet.svg +:name: fig-secret-key-packet +:alt: Depicts a box with white background and title "Secret-Key packet". In the center a box with white background and red frame is shown. Inside it several items are listed, separated by red dotted horizontal lines. The first three are "Version", "Creation Time", "Public-Key Algorithm" written in black. The fourth one is written in green and reads "Public Key Material" and has the green public key symbol at its right side. The fifth one is again written in black and reads "S2K Usage (Secret Key Encryption)". The sixth item reads "Secret Key Material", written in red and has the red private key symbol at its right side. + +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 + Version: 6 + Creation time: 2023-09-29 15:17:58 UTC + Pk algo: Ed25519 + Pk size: 256 bits + Fingerprint: AAA18CBB254685C58358320563FD37B67F3300F9FB0EC457378CD29F102698B3 + KeyID: AAA18CBB254685C5 + + Secret Key: + + Unencrypted + + 00000000 c5 CTB + 00000001 4b length + 00000002 06 version + 00000003 65 16 ea a6 creation_time + 00000007 1b pk_algo + 00000008 00 00 00 20 public_len + 0000000c 53 24 e9 43 ed25519_public + 00000010 af ab 15 f7 6e d5 b5 12 98 79 69 cd 1b 5d 10 65 + 00000020 eb e7 42 e2 ab 47 f4 86 b3 ae 65 3e + 0000002c 00 s2k_usage + 0000002d ef e1 99 ed25519_secret + 00000030 b5 5f 11 fb aa 93 e8 26 9d 3b b2 2d 72 20 7d ff + 00000040 bd 42 dd 4b e9 a3 36 81 3b a5 cc cf fb +``` + +The Secret-Key packet consists in large part of the actual cryptographic key data. Notice that its content is almost entirely the same as the Public-Key packet [seen in the previous chapter](zoom-public-key). Let's look at the packet field by field: + +- `CTB: 0xc5`[^CTB]: The [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers) for this packet. The binary representation of the value `0xc5` is `11000101`. 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: "5". This is the value for a Secret-Key packet, as shown in the list of [packet type IDs](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-types). +- `length: 0x4b`: The remaining length of this packet. + +[^CTB]: Sequoia uses the term CTB ({term}`Cipher Type Byte`) to refer to the [packet type ID](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-headers). + +The packet type id defines the semantics of the remaining data in the packet. We're looking at a Secret-Key packet, which is a kind of [Key Material Packet](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-key-material-packets). + +- `version: 0x06`: The key material is in version 6 format + +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-12.html#name-version-6-public-keys) + +- `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-12.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-12.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-12.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 + +This concludes the Public Key section of the packet. The remaining data follows the [Secret-Key packet format](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats): + +- `s2k_usage: 0x00`: The [*S2K usage* value](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption-s2k-u) of `0x00` specifies that the secret-key data is not encrypted +- `ed25519_secret`: [Algorithm-specific representation](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-part-for-ed2) of the secret key data (the format is based on the value of `pk_algo`). Because the private key material in this packet is not encrypted, this field + +```{tip} + +The overall structure of OpenPGP packets is described in the [Packet Syntax](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-packet-syntax) chapter of the RFC. +``` + +Note that the *Secret-Key packet* contains both the private and the public part of the key. + +### Secret-Subkey packet + +Further down in the "packet dump" of Alice's key, we see the encryption subkey, which we already inspected in its Public-Subkey packet format, [above](zoom-subkey-enc): + +```text +Secret-Subkey Packet, new CTB, 2 header bytes + 75 bytes + Version: 6 + Creation time: 2023-09-29 15:17:58 UTC + Pk algo: X25519 + Pk size: 256 bits + Fingerprint: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94 + KeyID: C0A58384A438E5A1 + + Secret Key: + + Unencrypted + + 00000000 c7 CTB + 00000001 4b length + 00000002 06 version + 00000003 65 16 ea a6 creation_time + 00000007 19 pk_algo + 00000008 00 00 00 20 public_len + 0000000c d1 ae 87 d7 x25519_public + 00000010 cc 42 af 99 34 c5 c2 5c ca fa b7 4a c8 43 fc 86 + 00000020 35 2a 46 01 f3 cc 00 f5 4a 09 3e 3f + 0000002c 00 s2k_usage + 0000002d 28 7d cd x25519_secret + 00000030 da 26 16 37 8d ea 24 c7 ce e7 70 c7 9b e5 6f 0a + 00000040 c9 77 fb bd 23 41 73 c9 57 5a bf 7c 4c +``` + +Again, this packet consists of the same content as its Public-Subkey equivalent, followed by two additional fields: + +- The "S2K usage" field, which indicated whether the private key material is encrypted. Like Alice's primary key (above), this subkey is not encrypted. +- The private key material: in this case, the algorithm-specific private key data consists of 32 bytes of `x25519_secret` data. + +As with the public key material, the difference between the format of this subkey packet and the private key packet is minimal: Only the packet type ID differs. + +## Bob's (encrypted) private key material + +Now we look at the primary key material packet of [Bob's key](bob-priv), which uses passphrase protection. + +```text +Secret-Key Packet, new CTB, 2 header bytes + 134 bytes + Version: 6 + Creation time: 2023-10-13 14:29:00 UTC + Pk algo: Ed25519 + Pk size: 256 bits + Fingerprint: BB289FB7A68DBFA8C384CCCDE2058E02D9C6CD2F3C7C56AE7FB53D971170BA83 + KeyID: BB289FB7A68DBFA8 + + Secret Key: + + Encrypted + S2K: Argon2id with t: 1, p: 4, m: 2^21, salt: 3B7F4B0EAC8B39625AB4D4BD690413C7 Sym. algo: AES-256 + + 00000000 c5 CTB + 00000001 86 length + 00000002 06 version + 00000003 65 29 54 2c creation_time + 00000007 1b pk_algo + 00000008 00 00 00 20 public_len + 0000000c 47 e7 c2 dc ed25519_public + 00000010 58 8e cb fd f2 49 90 66 ae aa 36 66 ca a9 55 2d + 00000020 71 88 7c 25 91 c3 75 73 1d 07 60 d6 + 0000002c fe s2k_usage + 0000002d 16 parameters_len + 0000002e 09 sym_algo + 0000002f 14 s2k_len + 00000030 04 s2k_type + 00000031 3b 7f 4b 0e ac 8b 39 62 5a b4 d4 bd 69 04 13 argon2_salt + 00000040 c7 + 00000041 01 argon2_t + 00000042 04 argon2_p + 00000043 15 argon2_m + 00000044 21 ff be fc f1 c5 9c 75 9d 1f d1 f8 encrypted_mpis + 00000050 19 e7 fd 47 55 e3 69 ff 2f e8 52 48 66 03 d3 37 + 00000060 52 7b 05 cb fa b1 f8 13 f7 f6 20 88 d6 f5 8b c4 + 00000070 b4 51 52 ba 6d f9 7c 1a ee 9f e6 b1 fb 63 d1 ca + 00000080 4a 3f 33 d9 2c c9 26 46 +``` + +The first portion of Bob's Secret-Key packet has the same structure as Alice's, but beginning at the `s2k_usage`, we see different data. The format of this data is described in [Secret-Key Packet Formats](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-packet-formats). + +- `s2k_usage: 0xfe`: [S2K usage](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-secret-key-encryption-s2k-u) is set to `AEAD`, here (decimal value 253). +- `parameters_len: 0x16` (decimal value: 22): "Cumulative length of all the following conditionally included string-to-key parameter fields." +- `sym_algo: 0x9`: [Symmetric-Key Algorithm](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetric-key-algorithms) specifies that AES 256 is used as the AEAD algorithm +- `s2k_len: 0x14` (decimal value 20): "[..] count of the size of the one field following this octet" + +The next set of data is the "string-to-key (S2K) specifier." Its format depends on the type. + +- `s2k_type: 0x04` [String-to-Key (S2K) Specifier Type](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-string-to-key-s2k-specifier-), set to *Argon2* here. + +The next fields are [specific to Argon2](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-argon2): + +- `argon2_salt`: "16-octet salt value" +- `argon2_t`: "number of passes t" +- `argon2_p`: "degree of parallelism p" +- `argon2_m`: "the exponent of the memory size" + +"Plain or encrypted multiprecision integers comprising the secret key data. This is algorithm-specific and described in Section 5.5.5. If the string-to-key usage octet is 253 (AEAD), then an AEAD authentication tag is at the end of that data." diff --git a/book/source/zoom/signatures.md b/book/source/zoom/signatures.md new file mode 100644 index 0000000..c748729 --- /dev/null +++ b/book/source/zoom/signatures.md @@ -0,0 +1,231 @@ + + +# 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)= +## 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 +```