<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.39 (Ruby 3.3.8) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

]>


<rfc ipr="trust200902" docName="draft-dkg-openpgp-stateless-cli-16" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title>Stateless OpenPGP Command Line Interface</title>

    <author initials="D. K." surname="Gillmor" fullname="Daniel Kahn Gillmor">
      <organization abbrev="ACLU">American Civil Liberties Union</organization>
      <address>
        <postal>
          <street>125 Broad St.</street>
          <city>New York</city>
          <region>NY</region>
          <code>10004</code>
          <country>USA</country>
        </postal>
        <email>dkg@fifthhorseman.net</email>
      </address>
    </author>
    <author initials="D." surname="Huigens" fullname="Daniel Huigens" role="editor">
      <organization>Proton AG</organization>
      <address>
        <postal>
          <street>Route de la Galaise 32</street>
          <city>Plan-les-Ouates</city>
          <code>1228</code>
          <country>Switzerland</country>
        </postal>
        <email>d.huigens@protonmail.com</email>
      </address>
    </author>

    <date year="2026" month="June" day="26"/>

    <area>int</area>
    <workgroup>openpgp</workgroup>
    <keyword>Internet-Draft</keyword>

    <abstract>


<?line 190?>

<t>This document defines a generic stateless command-line interface for dealing with OpenPGP messages, certificates, and secret key material, known as <spanx style="verb">sop</spanx>.
It aims for a minimal, well-structured API covering OpenPGP object security and maintenance of credentials and secrets.</t>



    </abstract>

    <note title="About This Document" removeInRFC="true">
      <t>
        The latest revision of this draft can be found at <eref target="https://dkg.gitlab.io/openpgp-stateless-cli/"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        OpenPGP Working Group mailing list (<eref target="mailto:openpgp@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/openpgp/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/openpgp/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://gitlab.com/dkg/openpgp-stateless-cli/"/>.</t>
    </note>


  </front>

  <middle>


<?line 195?>

<section anchor="introduction"><name>Introduction</name>

<t>Different OpenPGP implementations have many different requirements, which typically break down in two main categories: key/certificate management and object security.</t>

<t>The purpose of this document is to provide a "stateless" interface that can handle both object security side and key and certificate management in a way that would be usable by applications across the full OpenPGP lifecycle.</t>

<t>A priority for this interface is to facilitate interoperability testing for OpenPGP implementations, for example as described in <xref target="test-suite"/>.</t>

<t>This document defines a generic stateless command-line interface for dealing with OpenPGP messages, secret keys, and certificates, known here by the placeholder <spanx style="verb">sop</spanx>.
It aims for a minimal, well-structured API.</t>

<t>An OpenPGP implementation should not name its executable <spanx style="verb">sop</spanx> to implement this specification.  It just needs to provide a program that conforms to this interface.</t>

<t>A <spanx style="verb">sop</spanx> implementation should leave no trace on the system, and its behavior should not be affected by anything other than command-line arguments, environment variables, and input.</t>

<t>Inputs to <spanx style="verb">sop</spanx> are immutable inputs.
Any named files that it receives as input should only need read access, and it must not write to or modify any of its inputs.
The only places a <spanx style="verb">sop</spanx> implementation should write to are standard output and (in some special cases) a location specified by an <spanx style="verb">--*-out=</spanx> argument.</t>

<t>Obviously, the user (or consuming application) will need to manage persistent secret keys and certificates somehow,
but the goal of this interface is to separate out that task from the task of processing and handling OpenPGP objects.</t>

<t>While this document identifies a command-line interface,
the rough outlines of this interface should also be amenable to relatively straightforward library implementations in different languages.</t>

<t><xref target="libsop"/> offers a preliminary sketch of a C library interface that also has no implicit state.</t>

<section anchor="requirements-language"><name>Requirements Language</name>

<t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>

<?line -18?>

</section>
<section anchor="terminology"><name>Terminology</name>

<t>This document uses the term "key" to refer exclusively to OpenPGP Transferable Secret Keys (see <xref section="10.2" sectionFormat="of" target="RFC9580"/>).</t>

<t>It uses the term "certificate" to refer to OpenPGP Transferable Public Key (see <xref section="10.1" sectionFormat="of" target="RFC9580"/>).</t>

<t>The term "component key" means either the primary key or a subkey in any given OpenPGP certificate, as described in <xref target="Component-Keys"/>.</t>

<t>"Stateless" in "Stateless OpenPGP" means avoiding any sort of persistent and implicit state.
The user is responsible for managing all OpenPGP certificates and secret keys themselves,
and passing them to <spanx style="verb">sop</spanx> as needed.
The user should also not be concerned that any state could affect the underlying operations.</t>

<t>OpenPGP revocations can have "Reason for Revocation" (<xref section="5.2.3.31" sectionFormat="of" target="RFC9580"/>), which can be either "soft" or "hard".
The set of "soft" reasons is: "Key is superseded" and "Key is retired and no longer used".
All other reasons (and revocations that do not state a reason) are "hard" revocations.</t>

<t>This document refers to a special verification-only subset of the <spanx style="verb">sop</spanx> command-line interface as <spanx style="verb">sopv</spanx> (see <xref target="sopv"/> for more details).</t>

</section>
<section anchor="test-suite"><name>Using sop in a Test Suite</name>

<t>If an OpenPGP implementation provides a <spanx style="verb">sop</spanx> interface, it can be used to test interoperability (e.g., <xref target="OpenPGP-Interoperability-Test-Suite"></xref>).</t>

<t>Such an interop test suite can, for example, use custom code (<em>not</em> <spanx style="verb">sop</spanx>) to generate a new OpenPGP object that incorporates new primitives, and feed that object to a stable of <spanx style="verb">sop</spanx> implementations, to determine whether those implementations can consume the new form.</t>

<t>Or, the test suite can drive each <spanx style="verb">sop</spanx> implementation with a simple input, and observe which cryptographic primitives each implementation chooses to use as it produces output.</t>

<t>A simple self-test can be found in <xref target="simple-self-test"/>.</t>

</section>
<section anchor="semantics-vs-wire-format"><name>Semantics vs. Wire Format</name>

<t>The semantics of <spanx style="verb">sop</spanx> are deliberately simple and very high-level compared to the vast complexity and nuance available within the OpenPGP specification.
This reflects the perspective of nearly every piece of tooling that relies on OpenPGP to accomplish its task: most toolchains don't care about the specifics, they just want the high-level object security properties.</t>

<t>Given this framing, this document generally tries to avoid overconstraining the details of the wire format objects emitted, or what kinds of wire format structures should be acceptable or unacceptable.
This allows a test suite to evaluate and contrast the wire format choices made by different implementations in as close to their native configuration as possible.
It also makes it easier to promote interoperability by ensuring that the native wire formats emitted by one implementation can be consumed by another, without relying on their choices of wire format being constrained by this draft.</t>

<t>Where this draft does identify specific wire format requirements, that might be due to an ambiguity in the existing specifications (which maybe needs fixing elsewhere), or to a bug in this specification that could be improved.</t>

</section>
</section>
<section anchor="examples"><name>Examples</name>

<t>These examples show no error checking, but give a flavor of how <spanx style="verb">sop</spanx> might be used in practice from a shell.</t>

<t>The key and certificate files described in them (e.g., <spanx style="verb">alice.key</spanx>) could be for example those found in <xref target="I-D.draft-bre-openpgp-samples-01"/>.</t>

<figure><artwork><![CDATA[
sop generate-key "Alice Lovelace <alice@openpgp.example>" > alice.key
sop extract-cert < alice.key > alice.cert

sop generate-key "Bob Babbage <bob@openpgp.example>" > bob.key
sop extract-cert < bob.key > bob.cert

sop sign --as=text alice.key < statement.txt > statement.txt.asc
sop verify statement.txt.asc alice.cert < statement.txt

sop encrypt --sign-with=alice.key bob.cert < msg.eml > ciphertext.asc
sop decrypt bob.key < ciphertext.asc > cleartext.eml
]]></artwork></figure>

<t>See <xref target="failure-modes"/> for more information about errors and error handling.</t>

</section>
<section anchor="sopv"><name><spanx style="verb">sopv</spanx> Subset</name>

<t>While the primary goal of this document is to provide a full <spanx style="verb">sop</spanx> interface, as a special case, an implementer may choose to produce a version of the command-line interface that only supports OpenPGP signature verification.
As a shorthand, this document refers to such an interface as <spanx style="verb">sopv</spanx>, or "the <spanx style="verb">sopv</spanx> subset".
This can be useful for constrained environments where the only thing needed is signature verification, for example, system installation or update media.</t>

<t>A full implementation of <spanx style="verb">sop</spanx> by definition provides <spanx style="verb">sopv</spanx>.</t>

<t>Only the following subcommands and their associated options <bcp14>MUST</bcp14> be implemented for <spanx style="verb">sopv</spanx>:</t>

<t><list style="symbols">
  <t><spanx style="verb">version</spanx> (<xref target="version"/>)</t>
  <t><spanx style="verb">verify</spanx> (<xref target="verify"/>)</t>
  <t><spanx style="verb">inline-verify</spanx> (<xref target="inline-verify"/>)</t>
</list></t>

<section anchor="sopv-versioning"><name><spanx style="verb">sopv</spanx> Versioning</name>

<t>The abstract <spanx style="verb">sopv</spanx> interface is itself versioned using <xref target="SEMVER"/>.
The definition of the relevant subcommands and options specified in this document is known as <spanx style="verb">sopv</spanx> version 1.0.</t>

<t>If backward-incompatible changes are made to the <spanx style="verb">sopv</spanx> subset, the major version number will be increased.
If the <spanx style="verb">sopv</spanx> subset is extended without backward-incompatible changes, the minor version number will be increased.</t>

<t>Elements of the CLI relevant to <spanx style="verb">sopv</spanx> are annotated in this document with the <spanx style="verb">sopv</spanx> version in which they were introduced.</t>

<t>See also <xref target="sopv-changelog"/> for enumerated version history.</t>

</section>
</section>
<section anchor="universal-options"><name>Universal Options</name>

<t>Every invocation of <spanx style="verb">sop</spanx> or <spanx style="verb">sopv</spanx> <bcp14>MAY</bcp14> use the options described in this section, even though they are not specified in the synopsis for any specific subcommand.</t>

<section anchor="debug-emit-more-verbose-output"><name>--debug: emit more verbose output</name>

<t>When the <spanx style="verb">--debug</spanx> option is present, <spanx style="verb">sop</spanx> <bcp14>MAY</bcp14> emit implementation-specific debugging information to standard error.</t>

<t>A locale-aware, internationalized <spanx style="verb">sop</spanx> implementation will localize this debugging information.</t>

</section>
</section>
<section anchor="subcommands"><name>Subcommands</name>

<t><spanx style="verb">sop</spanx> uses a subcommand interface, similar to those popularized by systems like <spanx style="verb">git</spanx> and <spanx style="verb">svn</spanx>.</t>

<t>If the user supplies a subcommand that <spanx style="verb">sop</spanx> does not implement, it fails with <spanx style="verb">UNSUPPORTED_SUBCOMMAND</spanx>.
If a <spanx style="verb">sop</spanx> implementation does not handle a supplied option for a given subcommand, it fails with <spanx style="verb">UNSUPPORTED_OPTION</spanx>.</t>

<t>All subcommands that produce OpenPGP material on standard output produce ASCII-armored (<xref section="6" sectionFormat="of" target="RFC9580"/>) objects by default (except for <spanx style="verb">sop dearmor</spanx>).
These subcommands have a <spanx style="verb">--no-armor</spanx> option, which causes them to produce binary OpenPGP material instead.</t>

<t>All subcommands that accept OpenPGP material on input should be able to accept either ASCII-armored or binary inputs (see <xref target="optional-input-armoring"/>) and behave accordingly.</t>

<t>See <xref target="indirect-types"/> for details about how various forms of OpenPGP material are expected to be structured.</t>

<section anchor="meta-subcommands"><name>Meta Subcommands</name>

<t>The subcommands grouped in this section are related to the <spanx style="verb">sop</spanx> implementation itself.</t>

<section anchor="version"><name>version: Version Information</name>

<figure><artwork><![CDATA[
sop version [--backend|--extended|--sop-spec|--sopv]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: version information</t>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.0</t>
</list></t>

<t>This subcommand emits version information as UTF-8-encoded text.</t>

<t>With no arguments, the version string emitted should contain the name of the <spanx style="verb">sop</spanx> implementation, followed by a single space, followed by the version number.
A <spanx style="verb">sop</spanx> implementation should use a version number that respects an established standard that is easily comparable and parsable, like <xref target="SEMVER"/>.</t>

<t>If <spanx style="verb">--backend</spanx> is supplied, the implementation should produce a comparable line of implementation and version information about the primary underlying OpenPGP toolkit.</t>

<t>If <spanx style="verb">--extended</spanx> is supplied, the implementation may emit multiple lines of version information.
The first line <bcp14>MUST</bcp14> match the information produced by a simple invocation, but the rest of the text has no defined structure.</t>

<t>If <spanx style="verb">--sop-spec</spanx> is supplied, the implementation should emit a single line of text indicating the latest version of this draft that it targets, for example, <spanx style="verb">draft-dkg-openpgp-stateless-cli-06</spanx>.
If the implementation targets a specific draft but the implementer knows the implementation is incomplete, it should prefix the draft title with a <u>~</u>, for example: <spanx style="verb">~draft-dkg-openpgp-stateless-cli-06</spanx>.
The implementation <bcp14>MAY</bcp14> emit additional text about its relationship to the targeted draft on the lines following the versioned title.</t>

<t>If <spanx style="verb">--sopv</spanx> is supplied, the implementation should produce a single line with the implemented <xref target="SEMVER"/> version of the <spanx style="verb">sopv</spanx> interface subset (see <xref target="sopv"/>) that this implementation provides complete coverage for.
If the implementation does not provide complete coverage for any <spanx style="verb">sopv</spanx> interface, it should emit nothing on standard out and return <spanx style="verb">UNSUPPORTED_OPTION</spanx>.</t>

<t><spanx style="verb">--backend</spanx>, <spanx style="verb">--extended</spanx>, <spanx style="verb">--sop-spec</spanx>, and <spanx style="verb">--sopv</spanx> are mutually-exclusive options.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop version
ExampleSop 0.2.1
$ sop version --backend
LibExamplePGP 3.4.2
$ sop version --extended
ExampleSop 0.2.1
Running on MonkeyScript 4.5
LibExamplePGP 3.4.2
LibExampleCrypto 3.1.1
LibXCompression 4.0.2
See https://pgp.example/sop/ for more information
$ sop version --sop-spec
~draft-dkg-openpgp-stateless-cli-06

This implementation does not handle @FD: special designators for output.
$ sop version --sopv
1.0
$
]]></artwork></figure>

</section>
<section anchor="list-profiles"><name>list-profiles: Describe Available Profiles</name>

<figure><artwork><![CDATA[
sop list-profiles SUBCOMMAND
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: <spanx style="verb">PROFILELIST</spanx> (<xref target="profilelist"/>)</t>
  <t><spanx style="verb">sop</spanx> Introduction: 1.0</t>
</list></t>

<t>This subcommand emits a list of profiles supported by the identified subcommand.
The first profile listed is the default profile, as described in <xref target="profilelist"/>.</t>

<t>If the indicated <spanx style="verb">SUBCOMMAND</spanx> does not accept a <spanx style="verb">--profile</spanx> option, it returns <spanx style="verb">UNSUPPORTED_PROFILE</spanx>.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop list-profiles generate-key
default: use the implementer's recommendations
security: higher-security, maybe reduced performance
performance: higher-performance, maybe reduced security
rfc4880: use algorithms from RFC 4880 (alias: compatibility)
$
]]></artwork></figure>

</section>
</section>
<section anchor="key-and-certificate-management-subcommands"><name>Key and Certificate Management Subcommands</name>

<t>The subcommands grouped in this section are primarily intended to manipulate keys and certificates.</t>

<section anchor="generate-key"><name>generate-key: Generate a Secret Key</name>

<figure><artwork><![CDATA[
sop generate-key [--no-armor]
    [--with-key-password=PASSWORD]
    [--profile=PROFILE]
    [--signing-only]
    [--] [USERID...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
</list></t>

<t>Generate a single default OpenPGP key with zero or more User IDs.</t>

<t>The generated secret key <bcp14>SHOULD</bcp14> be usable for as much of the <spanx style="verb">sop</spanx> functionality as possible.
In particular:</t>

<t><list style="symbols">
  <t>It should be possible to extract an OpenPGP certificate from the key in <spanx style="verb">KEYS</spanx> with <spanx style="verb">sop extract-cert</spanx>.</t>
  <t>The key in <spanx style="verb">KEYS</spanx> should be able to create signatures (with <spanx style="verb">sop sign</spanx>) that are verifiable by using <spanx style="verb">sop verify</spanx> with the extracted certificate.</t>
  <t>Unless the <spanx style="verb">--signing-only</spanx> parameter is supplied, the key in <spanx style="verb">KEYS</spanx> should be able to decrypt messages (with <spanx style="verb">sop decrypt</spanx>) that are encrypted by using <spanx style="verb">sop encrypt</spanx> with the extracted certificate.</t>
</list></t>

<t>The detailed internal structure of the certificate is left to the discretion of the <spanx style="verb">sop</spanx> implementation.</t>

<t>If the <spanx style="verb">--with-key-password</spanx> option is supplied, the generated key will be password-protected (locked) with the supplied password.
Note that <spanx style="verb">PASSWORD</spanx> is an indirect data type from which the actual password is acquired (<xref target="indirect-types"/>).
See also the guidance on ensuring that the password is human-readable in <xref target="generating-human-readable"/>.</t>

<t>If no <spanx style="verb">--with-key-password</spanx> option is supplied, the generated key will be unprotected.</t>

<t>If the <spanx style="verb">--profile</spanx> argument is supplied and the indicated <spanx style="verb">PROFILE</spanx> is not supported by the implementation, <spanx style="verb">sop</spanx> will fail with <spanx style="verb">UNSUPPORTED_PROFILE</spanx>.</t>

<t>The presence of the <spanx style="verb">--signing-only</spanx> option is intended to create a key that is only capable of signing, not decrypting.
This is useful for deployments where only signing and verification are necessary.</t>

<t>If any of the <spanx style="verb">USERID</spanx> options are not valid <spanx style="verb">UTF-8</spanx>, <spanx style="verb">sop generate-key</spanx> fails with <spanx style="verb">EXPECTED_TEXT</spanx>.</t>

<t>If the implementation rejects any <spanx style="verb">USERID</spanx> option that is valid <spanx style="verb">UTF-8</spanx> (e.g., due to internal policy, see <xref target="userid"/>), <spanx style="verb">sop generate-key</spanx> fails with <spanx style="verb">BAD_DATA</spanx>.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop generate-key 'Alice Lovelace <alice@openpgp.example>' > alice.key
$ head -n1 < alice.key
-----BEGIN PGP PRIVATE KEY BLOCK-----
$
]]></artwork></figure>

</section>
<section anchor="change-key-password"><name>change-key-password: Update a Key's Password</name>

<figure><artwork><![CDATA[
sop change-key-password [--no-armor]
    [--new-key-password=PASSWORD]
    [--old-key-password=PASSWORD...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
  <t>Standard Output: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
</list></t>

<t>The output will be the same set of OpenPGP Transferable Secret Keys as the input, but with all secret key material locked according to the password indicated by the <spanx style="verb">--new-key-password</spanx> option (or, with no password at all, if <spanx style="verb">--new-key-password</spanx> is absent).
Note that <spanx style="verb">--old-key-password</spanx> can be supplied multiple times, and each supplied password will be tried as a means to unlock any locked key material encountered.
It will normalize a Transferable Secret Key to use a single password even if it originally had distinct passwords locking each of the component keys.</t>

<t>If any secret key packet is locked but cannot be unlocked with any of the supplied <spanx style="verb">--old-key-password</spanx> arguments, this subcommand should fail with <spanx style="verb">KEY_IS_PROTECTED</spanx>.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
# adding a password to an unlocked key:
$ sop change-key-password --new-key-password=@ENV:keypass \
  < unlocked.key > locked.key
# removing a password:
$ sop change-key-password --old-key-password=@ENV:keypass \
  < locked.key > unlocked.key
# changing a password:
$ sop change-key-password --old-key-password=@ENV:keypass \
  --new-key-password=@ENV:newpass < locked.key > refreshed.key
$
]]></artwork></figure>

</section>
<section anchor="revoke-key"><name>revoke-key: Create a Revocation Certificate</name>

<figure><artwork><![CDATA[
sop revoke-key [--no-armor]
    [--with-key-password=PASSWORD...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
  <t>Standard Output: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
</list></t>

<t>Generate a revocation certificate for each Transferable Secret Key found.
See <xref section="10.1.2" sectionFormat="of" target="RFC9580"/> for a discussion of common forms of revocation certificate.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop revoke-key < alice.key > alice-revoked.cert
$
]]></artwork></figure>

</section>
<section anchor="extract-cert"><name>extract-cert: Extract a Certificate from a Secret Key</name>

<figure><artwork><![CDATA[
sop extract-cert [--no-armor]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
  <t>Standard Output: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
</list></t>

<t>The output should contain one OpenPGP certificate in <spanx style="verb">CERTS</spanx> per OpenPGP Transferable Secret Key found in <spanx style="verb">KEYS</spanx>.
There is no guarantee what order the <spanx style="verb">CERTS</spanx> will be in.</t>

<t><spanx style="verb">sop extract-cert</spanx> <bcp14>SHOULD</bcp14> work even if any of the keys in <spanx style="verb">KEYS</spanx> is password-protected.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop extract-cert < alice.key > alice.cert
$ head -n1 < alice.cert
-----BEGIN PGP PUBLIC KEY BLOCK-----
$
]]></artwork></figure>

</section>
<section anchor="update-key"><name>update-key: Keep a Secret Key Up-To-Date</name>

<figure><artwork><![CDATA[
sop update-key [--no-armor]
    [--signing-only]
    [--revoke-deprecated-keys]
    [--no-added-capabilities]
    [--with-key-password=PASSWORD...]
    [--merge-certs=CERTS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
  <t>Standard Output: <spanx style="verb">KEYS</spanx> (<xref target="keys"/>)</t>
</list></t>

<t>The input OpenPGP Transferable Secret Keys that arrive on standard input will be updated by the implementation, and their updated forms will be produced on standard output.
This update will "fix" everything that the implementation knows how to fix to bring each Transferable Secret Key up to reasonable modern practice.
Each Transferable Secret Key output must be capable of signing, and (unless <spanx style="verb">--signing-only</spanx> is provided) capable of decryption.
The primary key of each Transferable Secret Key will not be changed in any way that affects its fingerprint.</t>

<t>If a <spanx style="verb">sop</spanx> implementation decides that an input key should itself be deprecated and replaced (e.g. due to an out-of-date or weaker-than-expected primary key), it <bcp14>MAY</bcp14> create an entirely new primary key and mark it as a replacement using the mechanism described in <xref target="I-D.ietf-openpgp-replacementkey"/>.
In this case, the output will contain both the (updated, now-deprecated) input key as well as the newly-generated replacement key.
The user IDs and attributes of the newly-generated replacement key <bcp14>SHOULD</bcp14> match those found in the input key.</t>

<t>This can also simultaneously revoke deprecated keys with the reason for revocation of "Key is superseded".
If the option <spanx style="verb">--revoke-deprecated-keys</spanx> is provided when the implementation does generate a new key for replacement, the input key will be revoked.
If the input contains multiple keys, and one of them is the replacement of any of the others, the deprecated keys in the equivalence group will be revoked.
If there are no replacement keys emitted in the output, the <spanx style="verb">--revoke-deprecated-keys</spanx> option is silently ignored.</t>

<t>One important aspect of <spanx style="verb">sop update-key</spanx> is how it handles advertisement of support for various OpenPGP capabilities (algorithms, mechanisms, etc).
All capabilities that the implementation knows it does not support, or knows to be weak and/or deprecated <bcp14>MUST</bcp14> be removed from the output Transferable Secret Keys.
This includes unknown/deprecated flags in the Features subpacket, and any unknown/deprecated algorithm IDs in algorithm preferences subpackets.
For example, an implementation compliant with <xref target="RFC9580"/> will never emit a Transferable Secret Key with a Preferred Hash Preferences subpacket that explicitly indicates support for <spanx style="verb">MD5</spanx>, <spanx style="verb">RIPEMD160</spanx>, or <spanx style="verb">SHA1</spanx>.</t>

<t>If <spanx style="verb">--no-added-capabilities</spanx> is not present, then any capability that the implementation supports and encourages that was not advertised in the input Transferable Secret Key <bcp14>MAY</bcp14> be added to the advertisements in the output Transferable Secret Key.
If <spanx style="verb">--no-added-capabilities</spanx> is present, then new capabilities <bcp14>MUST NOT</bcp14> be added to the advertised sets during the update.</t>

<t>Beyond cleanup of the advertised capabilities, <spanx style="verb">--signing-only</spanx>, and <spanx style="verb">--no-added-capabilities</spanx>, the choice of exactly what updates to do are up to the implementation.
It is expected that an implementer will document and describe the specific considerations and updates they make for this operation.
It is acceptable to propagate any non-critical unknown subpackets from old self-signatures to the new, replacement self-signatures.</t>

<t>Possible updates might include:</t>

<t><list style="symbols">
  <t>Refresh or replace any component key approaching expiry.</t>
  <t>Refresh any self-signature (including cross-sigs) that is approaching expiry.</t>
  <t>Refresh any self-signature (including cross-sigs) that is made using weak or risky algorithms.</t>
  <t>Correct any mistaken 2-octet hash prefix found in a signature (see <xref section="5.2.3" sectionFormat="of" target="RFC9580"/>).</t>
  <t>Ensure proof of "aliveness": if no self-signatures are more recent than some cutoff in the recent past, re-issue the same self-signatures.</t>
</list></t>

<t>If there is nothing to be updated because all the incoming Transferable Secret Keys are already in good shape, then the same set of Transferable Secret Keys will be emitted to standard output and <spanx style="verb">sop update-key</spanx> succeeds.</t>

<t>If any Transferable Secret Key cannot be fixed (for example, because its primary key uses a weak algorithm, or because the whole certificate is hard-revoked), <spanx style="verb">sop update-key</spanx> fails with <spanx style="verb">PRIMARY_KEY_BAD</spanx>, emits an explanation on stderr, and nothing on stdout.</t>

<t>If any secret key that needs to make a signature to update the key cannot be unlocked with any of the supplied <spanx style="verb">PASSWORD</spanx> objects, <spanx style="verb">sop update-key</spanx> fails with <spanx style="verb">KEY_IS_PROTECTED</spanx>, emits an explanation on stderr, and nothing on stdout.</t>

<t>If <spanx style="verb">--merge-certs</spanx> is supplied, and any of the <spanx style="verb">CERTS</spanx> objects correspond to the Transferable Secret Keys being updated, then any additional elements found in the corresponding <spanx style="verb">CERTS</spanx> are merged into the Transferable Secret Key before it is emitted.
This can be used, for example, to absorb a third-party certification into the Transferable Secret Key.</t>

<t>Example (keeping certificates fresh):</t>

<figure><artwork><![CDATA[
$ sop update-key < alice.key > alice-updated.key
$ mv alice-updated.key alice.key
$ sop extract-cert < alice.key > alice.cert
$
]]></artwork></figure>

<t>Example (advertising the intersection of features supported by two Stateless OpenPGP implementations, rendered here as <spanx style="verb">sop1</spanx> and <spanx style="verb">sop2</spanx>):</t>

<figure><artwork><![CDATA[
$ sop1 update-key < alice.key | sop2 update-key | \
  sop1 --no-added-capabilities update-key > alice-updated.key
$ mv alice-updated.key alice.key
$ sop1 extract-cert < alice.key > alice.cert
$
]]></artwork></figure>

</section>
<section anchor="merge-certs"><name>merge-certs: Merge OpenPGP Certificates</name>

<figure><artwork><![CDATA[
sop merge-certs [--no-armor]
    [--] CERTS [CERTS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
  <t>Standard Output: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
</list></t>

<t>The OpenPGP certificates on standard input will be produced on standard output, merged with the corresponding elements of any of the <spanx style="verb">CERTS</spanx> objects named on the command line.</t>

<t>This can be used, for example, to absorb a third-party certification into a certificate, or to update a certificate's feature advertisements without losing local annotations.</t>

<t>The certificates produced on standard output are only the certificates received on standard input.
If any certificate found via named command line parameters does not share a primary key with any standard input certificate, the certificate from the command line is ignored.</t>

<t>If any of the OpenPGP certificates on standard input share the same primary key, they are also merged and de-deduplicated on standard output.
If multiple OpenPGP certificates named on the command line share a primary key with one of the certificates on standard input, their certificate updates are cumulatively merged for output.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop merge-certs alice-certified-by-bob.cert \
  < alice.cert > alice-updated.cert
$ mv alice-updated.cert alice.cert
$
]]></artwork></figure>

</section>
</section>
<section anchor="user-identity-subcommands"><name>User Identity Subcommands</name>

<t>The subcommands in this section handle OpenPGP user identities.
OpenPGP certificates contain cryptographic certifications which bind text-based "User IDs" to primary key material, which is in turn cryptographically bound to additional key material.</t>

<t>These subcommands are related to the network of cryptographic identity assertions that has traditionally been called the "Web of Trust".
Note also the similarity in structure between these subcommands and <spanx style="verb">sop sign</spanx> (<xref target="sign"/>) and <spanx style="verb">sop verify</spanx> (<xref target="verify"/>)</t>

<section anchor="certify-userid"><name>certify-userid: Certify OpenPGP Certificate User IDs</name>

<figure><artwork><![CDATA[
sop certify-userid [--no-armor]
    --userid=USERID
    [--userid=USERID...]
    [--with-key-password=PASSWORD...]
    [--no-require-self-sig]
    [--] KEYS [KEYS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
  <t>Standard Output: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
</list></t>

<t>With each Transferable Secret Key in all <spanx style="verb">KEYS</spanx> objects, add a third-party certification to <spanx style="verb">CERTS</spanx> found on standard input, and emit the updated OpenPGP certificates (including the new certification(s)) on standard output.</t>

<t>If the caller does not specify at least one <spanx style="verb">--userid=USERID</spanx> option, <spanx style="verb">sop certify-userid</spanx> fails with <spanx style="verb">MISSING_ARG</spanx>.</t>

<t>If the certification-capable key of any Transferable Secret Key in <spanx style="verb">KEYS</spanx> is locked and cannot be unlocked by any of the supplied <spanx style="verb">PASSWORD</spanx>s, <spanx style="verb">sop certify-userid</spanx> fails with <spanx style="verb">KEY_IS_PROTECTED</spanx>.</t>

<t>If any incoming <spanx style="verb">CERTS</spanx> object does not already have all of the specified User IDs as valid, self-signed User IDs, then <spanx style="verb">sop certify-userid</spanx> fails with <spanx style="verb">CERT_USERID_NO_MATCH</spanx>, unless <spanx style="verb">--no-require-self-sig</spanx> is supplied.</t>

<t>If <spanx style="verb">--no-require-self-sig</spanx> is supplied, then each incoming OpenPGP certificate will have each specified User ID added to it (if it did not have it already), and certified directly, regardless of self-signatures.
This may be useful for associating a certificate with a specific identity even in cases where the certificate does not itself advertise the identity.</t>

<t>If any key in the <spanx style="verb">KEYS</spanx> objects is not capable of producing a certification, <spanx style="verb">sop certify-userid</spanx> will fail with <spanx style="verb">KEY_CANNOT_CERTIFY</spanx>.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop certify-userid \
  --userid="Alice Lovelace <alice@openpgp.example>" \
  bob.key < alice.cert > alice-signed-by-bob.cert
$
]]></artwork></figure>

<t>Example (adding a User ID to your own certificate):</t>

<figure><artwork><![CDATA[
$ sop certify-userid \
  --userid="Alice Lovelace <lovelace@business.example>" \
  alice.key < alice.cert > alice-updated.cert
$ sop update-key --merge-certs alice-updated.cert \
  < alice.key > alice-updated.key
$ mv alice-updated.key alice.key
$ rm alice-updated.cert
$ sop extract-cert < alice.key > alice.cert
$
]]></artwork></figure>

</section>
<section anchor="validate-userid"><name>validate-userid: Validate a User ID in an OpenPGP Certificate</name>

<figure><artwork><![CDATA[
sop validate-userid
    [--addr-spec-only]
    [--validate-at=DATE]
    [--] USERID CERTS [CERTS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">CERTS</spanx> (<xref target="certs"/>)</t>
  <t>Standard Output: none</t>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.2</t>
</list></t>

<t>Given a set of authority OpenPGP certificates on the command line, succeed if and only if all OpenPGP certificates on standard input are correctly bound by at least one valid signature from one authority to the <spanx style="verb">USERID</spanx> in question.</t>

<t>If <spanx style="verb">--addr-spec-only</spanx> is present, then the <spanx style="verb">USERID</spanx> is treated as an e-mail address, and matched only against the e-mail address part of each correctly bound User ID.
The rest of each correctly bound User ID is ignored.
If any correctly bound User ID is not a conventional OpenPGP User ID, it will not match with <spanx style="verb">--addr-spec-only</spanx> at all.
Note that <xref target="RFC9580"/> (and <xref target="RFC4880"/> and <xref target="RFC2440"/> before it) mislabeled an OpenPGP User ID as a <spanx style="verb">name-addr</spanx>, but that is likely to be wrong.</t>

<t>If <spanx style="verb">--validate-at</spanx> is present, then evaluate the validity of the User ID at the specified time.
If <spanx style="verb">--validate-at</spanx> is not present (or if it is present with the literal value <spanx style="verb">now</spanx>), the User ID validity is evaluated at the current time.</t>

<t>If any OpenPGP certificate in the <spanx style="verb">CERTS</spanx> on standard input does not have a correctly bound User ID that matches <spanx style="verb">USERID</spanx>, <spanx style="verb">sop validate-userid</spanx> fails with <spanx style="verb">CERT_USERID_NO_MATCH</spanx>.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ if sop validate-userid "Alice Lovelace <alice@openpgp.example>" \
  bob.cert < alice.cert; then echo Good; fi
Good
$ if sop validate-userid --addr-spec-only "alice@openpgp.example" \
  bob.cert < alice.cert; then echo Good; fi
Good
$
]]></artwork></figure>

</section>
</section>
<section anchor="messaging-subcommands"><name>Messaging Subcommands</name>

<t>The subcommands in this section handle OpenPGP messages: encrypting, decrypting, signing, and verifying.</t>

<section anchor="sign"><name>sign: Create Detached Signatures</name>

<figure><artwork><![CDATA[
sop sign [--no-armor] [--micalg-out=MICALG]
     [--with-key-password=PASSWORD...]
     [--as={binary|text}] [--] KEYS [KEYS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
  <t>Standard Output: <spanx style="verb">SIGNATURES</spanx> (<xref target="signature"/>)</t>
</list></t>

<t>Exactly one signature will be made by each key in the supplied <spanx style="verb">KEYS</spanx> arguments.</t>

<t><spanx style="verb">--as</spanx> defaults to <spanx style="verb">binary</spanx>.
If <spanx style="verb">--as=text</spanx> and the input <spanx style="verb">DATA</spanx> is not valid <spanx style="verb">UTF-8</spanx> (<xref target="utf8"/>), <spanx style="verb">sop sign</spanx> fails with <spanx style="verb">EXPECTED_TEXT</spanx>.</t>

<t><spanx style="verb">--as=binary</spanx> <bcp14>SHOULD</bcp14> result in OpenPGP signatures of type 0x00 ("Signature of a binary document").
<spanx style="verb">--as=text</spanx> <bcp14>SHOULD</bcp14> result in OpenPGP signatures of type 0x01 ("Signature of a canonical text document").
See <xref section="5.2.1" sectionFormat="of" target="RFC4880"/> for more details.</t>

<t>When generating PGP/MIME messages (<xref target="RFC3156"/>), it is useful to know what digest algorithm was used for the generated signature.
When <spanx style="verb">--micalg-out</spanx> is supplied, <spanx style="verb">sop sign</spanx> emits the digest algorithm used to the specified <spanx style="verb">MICALG</spanx> file in a way that can be used to populate the <spanx style="verb">micalg</spanx> parameter for the Content-Type (see <xref target="micalg"/>).
If the specified <spanx style="verb">MICALG</spanx> file already exists in the filesystem, <spanx style="verb">sop sign</spanx> will fail with <spanx style="verb">OUTPUT_EXISTS</spanx>.
When <spanx style="verb">--micalg-out</spanx> is supplied, the <spanx style="verb">DATA</spanx> on standard input should already be in canonical text form (7-bit clean, CRLF line endings, no trailing whitespace), as specified in <xref section="3" sectionFormat="of" target="RFC3156"/>.
If the incoming <spanx style="verb">DATA</spanx> does not already meet these requirements, <spanx style="verb">sop sign</spanx> will fail with <spanx style="verb">EXPECTED_TEXT</spanx>, regardless of any argument supplied for <spanx style="verb">--as</spanx>.
When <spanx style="verb">--micalg-out</spanx> is supplied, and multiple signatures are made but they do not all use the same digest algorithm, <spanx style="verb">sop sign</spanx> <bcp14>MUST</bcp14> emit the empty string to the designated <spanx style="verb">MICALG</spanx>.</t>

<t>If the signing key material in any key in the <spanx style="verb">KEYS</spanx> objects is password-protected, <spanx style="verb">sop sign</spanx> <bcp14>SHOULD</bcp14> try all supplied <spanx style="verb">--with-key-password</spanx> options to unlock the key material until it finds one that enables the use of the key for signing.
If none of the <spanx style="verb">PASSWORD</spanx> options unlock the key (or if no such option is supplied), <spanx style="verb">sop sign</spanx> will fail with <spanx style="verb">KEY_IS_PROTECTED</spanx>.
Note that <spanx style="verb">PASSWORD</spanx> is an indirect data type from which the actual password is acquired (<xref target="indirect-types"/>).
Note also the guidance for retrying variants of a non-human-readable password in <xref target="consuming-passwords"/>.</t>

<t>If any key in the <spanx style="verb">KEYS</spanx> objects is not capable of producing a signature, <spanx style="verb">sop sign</spanx> will fail with <spanx style="verb">KEY_CANNOT_SIGN</spanx>.</t>

<t><spanx style="verb">sop sign</spanx> <bcp14>MUST NOT</bcp14> produce any extra signatures beyond those from <spanx style="verb">KEYS</spanx> objects supplied on the command line.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop sign --as=text alice.key < message.txt > message.txt.asc
$ head -n1 < message.txt.asc
-----BEGIN PGP SIGNATURE-----
$
]]></artwork></figure>

</section>
<section anchor="verify"><name>verify: Verify Detached Signatures</name>

<figure><artwork><![CDATA[
sop verify [--not-before=DATE] [--not-after=DATE]
    [--] SIGNATURES CERTS [CERTS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
  <t>Standard Output: <spanx style="verb">VERIFICATIONS</spanx> (<xref target="verifications"/>)</t>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.0 (<spanx style="verb">VERIFICATIONS</spanx> output augmented in 1.1)</t>
</list></t>

<t><spanx style="verb">--not-before</spanx> and <spanx style="verb">--not-after</spanx> indicate that signatures with dates outside certain range <bcp14>MUST NOT</bcp14> be considered valid.</t>

<t><spanx style="verb">--not-before</spanx> defaults to the beginning of time.
Accepts the special value <spanx style="verb">-</spanx> to indicate the beginning of time (i.e., no lower boundary).</t>

<t><spanx style="verb">--not-after</spanx> defaults to the current system time (<spanx style="verb">now</spanx>).
Accepts the special value <spanx style="verb">-</spanx> to indicate the end of time (i.e., no upper boundary).</t>

<t><spanx style="verb">sop verify</spanx> only returns <spanx style="verb">OK</spanx> if at least one certificate included in any <spanx style="verb">CERTS</spanx> object made a valid signature in the time window specified over the <spanx style="verb">DATA</spanx> supplied.</t>

<t>For details about the valid signatures, the user <bcp14>MUST</bcp14> inspect the <spanx style="verb">VERIFICATIONS</spanx> output.</t>

<t>If no <spanx style="verb">CERTS</spanx> are supplied, <spanx style="verb">sop verify</spanx> fails with <spanx style="verb">MISSING_ARG</spanx>.</t>

<t>If no valid signatures are found, <spanx style="verb">sop verify</spanx> fails with <spanx style="verb">NO_SIGNATURE</spanx>.
In this case, <spanx style="verb">sop verify</spanx> <bcp14>MAY</bcp14> emit some human-readable explanation to standard error about why no valid signatures were found, see <xref target="explaining-non-verification"/>.</t>

<t>See <xref target="signature-verification"/> for more details about signature verification.</t>

<t>Example:</t>

<t>(In this example, we see signature verification succeed first, and then fail on a modified version of the message.)</t>

<figure><artwork><![CDATA[
$ sop verify message.txt.asc alice.cert < message.txt
2019-10-29T18:36:45Z EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E mode:text {"signers": ["alice.cert"]}
$ echo $?
0
$ tr a-z A-Z < message.txt | sop verify message.txt.asc alice.cert
$ echo $?
3
$
]]></artwork></figure>

</section>
<section anchor="encrypt"><name>encrypt: Encrypt a Message</name>

<figure><artwork><![CDATA[
sop encrypt [--as={binary|text}]
    [--no-armor]
    [--with-password=PASSWORD...]
    [--sign-with=KEYS...]
    [--with-key-password=PASSWORD...]
    [--profile=PROFILE]
    [--session-key-out=SESSIONKEY]
    [--for={storage|communications|any}]
    [--] [CERTS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
  <t>Standard Output: <spanx style="verb">CIPHERTEXT</spanx> (<xref target="ciphertext"/>)</t>
</list></t>

<t><spanx style="verb">--as</spanx> defaults to <spanx style="verb">binary</spanx>.
The setting of <spanx style="verb">--as</spanx> corresponds to the one octet format field found in the Literal Data packet at the core of the output <spanx style="verb">CIPHERTEXT</spanx>.
If <spanx style="verb">--as</spanx> is set to <spanx style="verb">binary</spanx>, the octet is <spanx style="verb">b</spanx> (<spanx style="verb">0x62</spanx>).
If it is <spanx style="verb">text</spanx>, the format octet is <spanx style="verb">u</spanx> (<spanx style="verb">0x75</spanx>).</t>

<t><spanx style="verb">--with-password</spanx> enables symmetric encryption (and can be used multiple times if multiple passwords are desired).</t>

<t><spanx style="verb">--sign-with</spanx> creates exactly one signature by for each secret key found in the supplied <spanx style="verb">KEYS</spanx> object (this can also be used multiple times if signatures from keys found in separate files are desired).
If any key in any supplied <spanx style="verb">KEYS</spanx> object is not capable of producing a signature, <spanx style="verb">sop sign</spanx> will fail with <spanx style="verb">KEY_CANNOT_SIGN</spanx>.
If any signing key material in any supplied <spanx style="verb">KEYS</spanx> object is password-protected, <spanx style="verb">sop encrypt</spanx> <bcp14>SHOULD</bcp14> try all supplied <spanx style="verb">--with-key-password</spanx> options to unlock the key material until it finds one that enables the use of the key for signing.
If none of the <spanx style="verb">--with-key-password=PASSWORD</spanx> options can unlock any locked signing key material (or if no such option is supplied), <spanx style="verb">sop encrypt</spanx> will fail with <spanx style="verb">KEY_IS_PROTECTED</spanx>.
All signatures made must be placed inside the encryption produced by <spanx style="verb">sop encrypt</spanx>.</t>

<t>Note that both <spanx style="verb">--with-password</spanx> and <spanx style="verb">--with-key-password</spanx> supply <spanx style="verb">PASSWORD</spanx> arguments, but they do so in different contexts which are not interchangeable.
A <spanx style="verb">PASSWORD</spanx> supplied for symmetric encryption (<spanx style="verb">--with-password</spanx>) <bcp14>MUST NOT</bcp14> be used to try to unlock a signing key (<spanx style="verb">--with-key-password</spanx>) and a <spanx style="verb">PASSWORD</spanx> supplied to unlock a signing key <bcp14>MUST NOT</bcp14> be used to symmetrically encrypt the message.
Regardless of context, each <spanx style="verb">PASSWORD</spanx> argument is presented as an indirect data type from which the actual password is acquired (<xref target="indirect-types"/>).
If <spanx style="verb">sop encrypt</spanx> encounters a password which is not a valid <spanx style="verb">UTF-8</spanx> string (<xref target="utf8"/>), or is otherwise not robust in its representation to humans,
it fails with <spanx style="verb">PASSWORD_NOT_HUMAN_READABLE</spanx>.
If <spanx style="verb">sop encrypt</spanx> sees trailing whitespace at the end of a password,
it will trim the trailing whitespace before using the password.
See <xref target="human-readable-passwords"/> for more discussion about passwords.</t>

<t>If <spanx style="verb">--as</spanx> is set to <spanx style="verb">binary</spanx>, then <spanx style="verb">--sign-with</spanx> will sign as a binary document (OpenPGP signature type <spanx style="verb">0x00</spanx>).</t>

<t>If <spanx style="verb">--as</spanx> is set to <spanx style="verb">text</spanx>, then <spanx style="verb">--sign-with</spanx> will sign as a canonical text document (OpenPGP signature type <spanx style="verb">0x01</spanx>).
In this case, if the input <spanx style="verb">DATA</spanx> is not valid <spanx style="verb">UTF-8</spanx>  (<xref target="utf8"/>), <spanx style="verb">sop encrypt</spanx> fails with <spanx style="verb">EXPECTED_TEXT</spanx>.</t>

<t>If <spanx style="verb">--sign-with</spanx> is supplied for input <spanx style="verb">DATA</spanx> that is not valid <spanx style="verb">UTF-8</spanx>, <spanx style="verb">sop encrypt</spanx> <bcp14>MAY</bcp14> sign as a binary document (OpenPGP signature type <spanx style="verb">0x00</spanx>).</t>

<t><spanx style="verb">sop encrypt</spanx> <bcp14>MUST NOT</bcp14> produce any extra signatures beyond those from <spanx style="verb">KEYS</spanx> objects identified by <spanx style="verb">--sign-with</spanx>.</t>

<t>The resulting <spanx style="verb">CIPHERTEXT</spanx> should be decryptable by the secret keys corresponding to every certificate included in all <spanx style="verb">CERTS</spanx>, as well as each password given with <spanx style="verb">--with-password</spanx>.</t>

<t>If no <spanx style="verb">CERTS</spanx> or <spanx style="verb">--with-password</spanx> options are present, <spanx style="verb">sop encrypt</spanx> fails with <spanx style="verb">MISSING_ARG</spanx>.</t>

<t>If at least one of the identified certificates requires encryption to an unsupported asymmetric algorithm, <spanx style="verb">sop encrypt</spanx> fails with <spanx style="verb">UNSUPPORTED_ASYMMETRIC_ALGO</spanx>.</t>

<t>If <spanx style="verb">--for</spanx> is explicitly supplied, it is used to select the suitable encryption-capable component key(s) from each recipient certificate, based on the Key Flags subpacket (see <xref section="5.2.3.29" sectionFormat="of" target="RFC9580"/>) in the certificate's subkey binding signatures or primary key direct key signature.
<spanx style="verb">communications</spanx> should select only from component keys with flag 0x04 set, <spanx style="verb">storage</spanx> should select only from component keys with flag 0x08 set, and <spanx style="verb">any</spanx> should select from component keys with either flag set.
If it is not explicitly supplied, <spanx style="verb">--for</spanx> defaults to <spanx style="verb">any</spanx>.
If no recipient certificates are supplied (i.e., only <spanx style="verb">--with-password</spanx> is used), then <spanx style="verb">--for</spanx> has no effect.</t>

<t>If at least one of the identified certificates is not encryption-capable (e.g., revoked, expired, no matching encryption-capable flags on any componnt key), <spanx style="verb">sop encrypt</spanx> fails with <spanx style="verb">CERT_CANNOT_ENCRYPT</spanx>.</t>

<t>If the <spanx style="verb">--profile</spanx> argument is supplied and the indicated <spanx style="verb">PROFILE</spanx> is not supported by the implementation, <spanx style="verb">sop</spanx> will fail with <spanx style="verb">UNSUPPORTED_PROFILE</spanx>.
The use of a profile for this subcommand allows an implementation faced with parametric or algorithmic choices to make a decision coarsely guided by the operator.
For example, when encrypting with a password, there is no knowledge about the capabilities of the recipient, and an implementation may prefer cryptographically modern algorithms, or it may prefer more broad compatibility.
In the event that a known recipient (i.e., one of the <spanx style="verb">CERTS</spanx>) explicitly indicates a lack of support for one of the features preferred by the indicated profile, the implementation <bcp14>SHOULD</bcp14> conform to the recipient's advertised capabilities where possible.</t>

<t>If <spanx style="verb">--session-key-out</spanx> argument is supplied, the session key generated for this encrypted message will be written to the indicated location.
This can be useful, for example, when Alice encrypts a message to Bob, but also wants to retain the ability to read it without having any of her own secret key material available (see <xref section="9.1" sectionFormat="of" target="I-D.ietf-lamps-e2e-mail-guidance-11"/>).</t>

<t>If <spanx style="verb">sop encrypt</spanx> fails for any reason, it emits no <spanx style="verb">CIPHERTEXT</spanx>.</t>

<t>Example:</t>

<t>(In this example, <spanx style="verb">bob.bin</spanx> is a file containing Bob's binary-formatted OpenPGP certificate.
Alice is encrypting a message to both herself and Bob.)</t>

<figure><artwork><![CDATA[
$ sop encrypt --as=text --sign-with=alice.key \
  alice.asc bob.bin < message.eml > encrypted.asc
$ head -n1 encrypted.asc
-----BEGIN PGP MESSAGE-----
$
]]></artwork></figure>

</section>
<section anchor="decrypt"><name>decrypt: Decrypt a Message</name>

<figure><artwork><![CDATA[
sop decrypt [--session-key-out=SESSIONKEY]
    [--with-session-key=SESSIONKEY...]
    [--with-password=PASSWORD...]
    [--with-key-password=PASSWORD...]
    [--verifications-out=VERIFICATIONS
     [--verify-with=CERTS...]
     [--verify-not-before=DATE]
     [--verify-not-after=DATE] ]
    [--] [KEYS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">CIPHERTEXT</spanx> (<xref target="ciphertext"/>)</t>
  <t>Standard Output: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
</list></t>

<t>The caller can ask <spanx style="verb">sop</spanx> for the session key discovered during decryption by supplying the <spanx style="verb">--session-key-out</spanx> option.
If the specified file already exists in the filesystem, <spanx style="verb">sop decrypt</spanx> will fail with <spanx style="verb">OUTPUT_EXISTS</spanx>.
When decryption is successful, <spanx style="verb">sop decrypt</spanx> writes the discovered session key to the specified file.</t>

<t><spanx style="verb">--with-session-key</spanx> enables decryption of the <spanx style="verb">CIPHERTEXT</spanx> using the session key directly against the <spanx style="verb">SEIPD</spanx> packet.
This option can be used multiple times if several possible session keys should be tried.
<spanx style="verb">SESSIONKEY</spanx> is an indirect data type from which the actual <spanx style="verb">sessionkey</spanx> value is acquired (<xref target="indirect-types"/>).</t>

<t><spanx style="verb">--with-password</spanx> enables decryption based on any <spanx style="verb">SKESK</spanx> (<xref section="5.3" sectionFormat="of" target="RFC9580"/>) packets in the <spanx style="verb">CIPHERTEXT</spanx>.
This option can be used multiple times if the user wants to try more than one password.</t>

<t><spanx style="verb">--with-key-password</spanx> lets the user use password-protected (locked) secret key material.
If the decryption-capable secret key material in any key in the <spanx style="verb">KEYS</spanx> objects is password-protected, <spanx style="verb">sop decrypt</spanx> <bcp14>SHOULD</bcp14> try all supplied <spanx style="verb">--with-key-password</spanx> options to unlock the key material until it finds one that enables the use of the key for decryption.
If none of the <spanx style="verb">--with-key-password</spanx> options unlock the key (or if no such option is supplied), and the message cannot be decrypted with any other <spanx style="verb">KEYS</spanx>, <spanx style="verb">--with-session-key</spanx>, or <spanx style="verb">--with-password</spanx> options, <spanx style="verb">sop decrypt</spanx> will fail with <spanx style="verb">KEY_IS_PROTECTED</spanx>.</t>

<t>Note that the two kinds of <spanx style="verb">PASSWORD</spanx> options are for different domains: <spanx style="verb">--with-password</spanx> is for unlocking an <spanx style="verb">SKESK</spanx>, and <spanx style="verb">--with-key-password</spanx> is for unlocking secret key material in <spanx style="verb">KEYS</spanx>.
<spanx style="verb">sop decrypt</spanx> <bcp14>SHOULD NOT</bcp14> apply the <spanx style="verb">--with-key-password</spanx> argument to any <spanx style="verb">SKESK</spanx>, or the <spanx style="verb">--with-password</spanx> argument to any <spanx style="verb">KEYS</spanx>.</t>

<t>Each <spanx style="verb">PASSWORD</spanx> argument is an indirect data type from which the actual password is acquired (<xref target="indirect-types"/>).
If <spanx style="verb">sop decrypt</spanx> tries and fails to use a password supplied by a <spanx style="verb">PASSWORD</spanx>,
and it observes that there is trailing <spanx style="verb">UTF-8</spanx> whitespace at the end of the password,
it will retry with the trailing whitespace stripped.
See <xref target="consuming-passwords"/> for more discussion about consuming password-protected key material.</t>

<t><spanx style="verb">--verifications-out</spanx> produces signature verification status to the designated file.
If the designated file already exists in the filesystem, <spanx style="verb">sop decrypt</spanx> will fail with <spanx style="verb">OUTPUT_EXISTS</spanx>.</t>

<t>The return code of <spanx style="verb">sop decrypt</spanx> is not affected by the results of signature verification.
The caller <bcp14>MUST</bcp14> check the returned <spanx style="verb">VERIFICATIONS</spanx> to confirm signature status.
An empty <spanx style="verb">VERIFICATIONS</spanx> output indicates that no valid signatures were found.</t>

<t>If no valid signatures were found, but <spanx style="verb">--verifications-out</spanx> was supplied, <spanx style="verb">sop decrypt</spanx> <bcp14>MAY</bcp14> emit some human-readable explanation to standard error about why no valid signatures were found, see <xref target="explaining-non-verification"/>.</t>

<t><spanx style="verb">--verify-with</spanx> identifies a set of certificates whose signatures would be acceptable for signatures over this message.</t>

<t>If the caller is interested in signature verification, both <spanx style="verb">--verifications-out</spanx> and at least one <spanx style="verb">--verify-with</spanx> must be supplied.
If only one of these options is supplied, <spanx style="verb">sop decrypt</spanx> fails with <spanx style="verb">INCOMPLETE_VERIFICATION</spanx>.</t>

<t><spanx style="verb">--verify-not-before</spanx> and <spanx style="verb">--verify-not-after</spanx> provide a date range for acceptable signatures,
by analogy with the options for <spanx style="verb">sop verify</spanx> (see <xref target="verify"/>).
They should only be supplied when doing signature verification.</t>

<t>See <xref target="signature-verification"/> for more details about signature verification.</t>

<t>If no <spanx style="verb">KEYS</spanx> or <spanx style="verb">--with-password</spanx> or <spanx style="verb">--with-session-key</spanx> options are present, <spanx style="verb">sop decrypt</spanx> fails with <spanx style="verb">MISSING_ARG</spanx>.</t>

<t>If unable to decrypt, <spanx style="verb">sop decrypt</spanx> fails with <spanx style="verb">CANNOT_DECRYPT</spanx>.</t>

<t><spanx style="verb">sop decrypt</spanx> only emits cleartext to Standard Output that was successfully decrypted.</t>

<t>Example:</t>

<t>(In this example, Alice stashes and reuses the session key of an encrypted message.)</t>

<figure><artwork><![CDATA[
$ sop decrypt --session-key-out=session.key \
  alice.key < ciphertext.asc > cleartext.out
$ ls -l ciphertext.asc cleartext.out
-rw-r--r-- 1 user user   321 Oct 28 01:34 ciphertext.asc
-rw-r--r-- 1 user user   285 Oct 28 01:34 cleartext.out
$ sop decrypt --with-session-key=session.key \
  < ciphertext.asc > cleartext2.out
$ diff cleartext.out cleartext2.out
$
]]></artwork></figure>

<section anchor="historic-options-for-sop-decrypt"><name>Historic Options for sop decrypt</name>

<t>The <spanx style="verb">sop decrypt</spanx> option <spanx style="verb">--verifications-out</spanx> used to be named <spanx style="verb">--verify-out</spanx>.
An implementation <bcp14>SHOULD</bcp14> accept either form of this option, and <bcp14>SHOULD</bcp14> produce a deprecation warning to standard error if the old form is used.</t>

</section>
</section>
<section anchor="inline-detach"><name>inline-detach: Split Signatures from an Inline-Signed Message</name>

<figure><artwork><![CDATA[
sop inline-detach [--no-armor] --signatures-out=SIGNATURES
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">INLINESIGNED</spanx></t>
  <t>Standard Output: <spanx style="verb">DATA</spanx> (the message without any signatures)</t>
</list></t>

<t>In some contexts, the user may expect an inline-signed message of some form or another (<spanx style="verb">INLINESIGNED</spanx>, see <xref target="inlinesigned"/>) rather than a message and its detached signature.
<spanx style="verb">sop inline-detach</spanx> takes such an inline-signed message on standard input, and splits it into:</t>

<t><list style="symbols">
  <t>the potentially signed material on standard output, and</t>
  <t>a detached signature block to the destination identified by <spanx style="verb">--signatures-out</spanx></t>
</list></t>

<t>Note that no cryptographic verification of the signatures is done by this subcommand.
Once the inline-signed message is separated, verification of the detached signature can be done with <spanx style="verb">sop verify</spanx>.</t>

<t>If no <spanx style="verb">--signatures-out</spanx> is supplied, <spanx style="verb">sop inline-detach</spanx> fails with <spanx style="verb">MISSING_ARG</spanx>.</t>

<t>Note that there may be more than one Signature packet in an inline-signed message.
All signatures found in the inline-signed message will be emitted to the <spanx style="verb">--signatures-out</spanx> destination.</t>

<t>If the inline-signed message uses the Cleartext Signature Framework, it may be dash-escaped (see <xref section="7.2" sectionFormat="of" target="RFC9580"/>).
The output of <spanx style="verb">sop inline-detach</spanx> will have any dash-escaping removed.</t>

<t>If the input is not an <spanx style="verb">INLINESIGNED</spanx> message, <spanx style="verb">sop inline-detach</spanx> fails with <spanx style="verb">BAD_DATA</spanx>.
If the input contains more than one object that could be interpreted as an <spanx style="verb">INLINESIGNED</spanx> message, <spanx style="verb">sop inline-detach</spanx> also fails with <spanx style="verb">BAD_DATA</spanx>.
A <spanx style="verb">sop</spanx> implementation <bcp14>MAY</bcp14> accept (and discard) leading and trailing data when the incoming <spanx style="verb">INLINESIGNED</spanx> message uses the Cleartext Signature Framework.</t>

<t>If the file designated by <spanx style="verb">--signatures-out</spanx> already exists in the filesystem, <spanx style="verb">sop inline-detach</spanx> will fail with <spanx style="verb">OUTPUT_EXISTS</spanx>.</t>

<t>Note that <spanx style="verb">--no-armor</spanx> here governs the data written to the <spanx style="verb">--signatures-out</spanx> destination.
Standard output is always the raw message, not an OpenPGP packet.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop inline-detach --signatures-out=Release.sig < InRelease >Release
$ sop verify Release.sig archive-keyring.pgp < Release
$
]]></artwork></figure>

</section>
<section anchor="inline-verify"><name>inline-verify: Verify an Inline-Signed Message</name>

<figure><artwork><![CDATA[
sop inline-verify [--not-before=DATE] [--not-after=DATE]
    [--verifications-out=VERIFICATIONS]
    [--] CERTS [CERTS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">INLINESIGNED</spanx> (<xref target="inlinesigned"/>)</t>
  <t>Standard Output: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.0 (<spanx style="verb">VERIFICATIONS</spanx> output augmented in 1.1)</t>
</list></t>

<t>This command is similar to <spanx style="verb">sop verify</spanx> (<xref target="verify"/>) except that it takes an <spanx style="verb">INLINESIGNED</spanx> message (see <xref target="inlinesigned"/>) and produces the message body (without signatures) on standard output.
It is also similar to <spanx style="verb">sop inline-detach</spanx> (<xref target="inline-detach"/>) except that it actually performs signature verification.</t>

<t><spanx style="verb">--not-before</spanx> and <spanx style="verb">--not-after</spanx> indicate that signatures with dates outside certain range <bcp14>MUST NOT</bcp14> be considered valid.
See <xref target="verify"/> for their syntax and defaults.</t>

<t><spanx style="verb">sop inline-verify</spanx> only returns <spanx style="verb">OK</spanx> if <spanx style="verb">INLINESIGNED</spanx> contains at least one valid signature made during the time window specified by a certificate included in any <spanx style="verb">CERTS</spanx> object.</t>

<t>For details about the valid signatures, the user <bcp14>MUST</bcp14> inspect the <spanx style="verb">VERIFICATIONS</spanx> output.</t>

<t>If no <spanx style="verb">CERTS</spanx> are supplied, <spanx style="verb">sop inline-verify</spanx> fails with <spanx style="verb">MISSING_ARG</spanx>.</t>

<t>If no valid signatures are found, <spanx style="verb">sop inline-verify</spanx> fails with <spanx style="verb">NO_SIGNATURE</spanx> and emits nothing on standard output.
In this case, <spanx style="verb">sop inline-verify</spanx> <bcp14>MAY</bcp14> emit some human-readable explanation to standard error about why no valid signatures were found, see <xref target="explaining-non-verification"/>.</t>

<t>See <xref target="signature-verification"/> for more details about signature verification.</t>

<t>Example:</t>

<t>(In this example, we see signature verification succeed first, and then fail on a modified version of the message.)</t>

<figure><artwork><![CDATA[
$ sop inline-verify -- alice.cert < message.txt
Hello, world!
$ echo $?
0
$ sed s/Hello/Goodbye/ < message.txt | sop inline-verify -- alice.cert
$ echo $?
3
$
]]></artwork></figure>

</section>
<section anchor="inline-sign"><name>inline-sign: Create an Inline-Signed Message</name>

<figure><artwork><![CDATA[
sop inline-sign [--no-armor]
     [--with-key-password=PASSWORD...]
     [--as={binary|text|clearsigned}]
     [--] KEYS [KEYS...]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
  <t>Standard Output: <spanx style="verb">INLINESIGNED</spanx> (<xref target="inlinesigned"/>)</t>
</list></t>

<t>Exactly one signature will be made by each key in the supplied <spanx style="verb">KEYS</spanx> arguments.</t>

<t>The generated output stream will be an inline-signed message, by default producing an OpenPGP "Signed Message" packet stream.</t>

<t><spanx style="verb">--as</spanx> defaults to <spanx style="verb">binary</spanx>.
If <spanx style="verb">--as=</spanx> is set to either <spanx style="verb">text</spanx> or <spanx style="verb">clearsigned</spanx>, and the input <spanx style="verb">DATA</spanx> is not valid <spanx style="verb">UTF-8</spanx> (<xref target="utf8"/>), <spanx style="verb">sop inline-sign</spanx> fails with <spanx style="verb">EXPECTED_TEXT</spanx>.</t>

<t><spanx style="verb">--as=binary</spanx> <bcp14>SHOULD</bcp14> result in OpenPGP signatures of type 0x00 ("Signature of a binary document", see <xref section="5.2.1.1" sectionFormat="of" target="RFC9580"/>).
<spanx style="verb">--as=text</spanx> <bcp14>SHOULD</bcp14> result in an OpenPGP signature of type 0x01 ("Signature of a canonical text document" see <xref section="5.2.1.2" sectionFormat="of" target="RFC9580"/>).
<spanx style="verb">--as=clearsigned</spanx> <bcp14>SHOULD</bcp14> behave the same way as <spanx style="verb">--as=text</spanx> except that it produces an output stream using the Cleartext Signature Framework (see <xref section="7" sectionFormat="of" target="RFC9580"/> and <xref target="csf-risks"/>).</t>

<t>If both <spanx style="verb">--no-armor</spanx> and <spanx style="verb">--as=clearsigned</spanx>  are supplied, <spanx style="verb">sop inline-sign</spanx> fails with <spanx style="verb">INCOMPATIBLE_OPTIONS</spanx>.</t>

<t>If the signing key material in any key in the <spanx style="verb">KEYS</spanx> objects is password-protected, <spanx style="verb">sop inline-sign</spanx> <bcp14>SHOULD</bcp14> try all supplied <spanx style="verb">--with-key-password</spanx> options to unlock the key material until it finds one that enables the use of the key for signing.
If none of the <spanx style="verb">PASSWORD</spanx> options unlock the key (or if no such option is supplied), <spanx style="verb">sop inline-sign</spanx> will fail with <spanx style="verb">KEY_IS_PROTECTED</spanx>.
Note that <spanx style="verb">PASSWORD</spanx> is an indirect data type from which the actual password is acquired (<xref target="indirect-types"/>).
Note also the guidance for retrying variants of a non-human-readable password in <xref target="consuming-passwords"/>.</t>

<t>If any key in the <spanx style="verb">KEYS</spanx> objects is not capable of producing a signature, <spanx style="verb">sop inline-sign</spanx> will fail with <spanx style="verb">KEY_CANNOT_SIGN</spanx>.</t>

<t><spanx style="verb">sop inline-sign</spanx> <bcp14>MUST NOT</bcp14> produce any extra signatures beyond those from <spanx style="verb">KEYS</spanx> objects supplied on the command line.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop inline-sign --as=clearsigned alice.key \
  < message.txt > message-signed.txt
$ head -n5 < message-signed.txt
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

This is the message.
-----BEGIN PGP SIGNATURE-----
$
]]></artwork></figure>

</section>
</section>
<section anchor="transport-subcommands"><name>Transport Subcommands</name>

<t>The commands in this section handle manipulating OpenPGP objects for transport: armoring and dearmoring for 7-bit cleanness and compactness, respectively.</t>

<section anchor="armor-convert-binary-to-ascii"><name>armor: Convert Binary to ASCII</name>

<figure><artwork><![CDATA[
sop armor
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: OpenPGP material (<spanx style="verb">SIGNATURES</spanx>, <spanx style="verb">KEYS</spanx>, <spanx style="verb">CERTS</spanx>, <spanx style="verb">CIPHERTEXT</spanx>, or <spanx style="verb">INLINESIGNED</spanx>)</t>
  <t>Standard Output: the same material with ASCII-armoring added, if not already present</t>
</list></t>

<t><spanx style="verb">sop armor</spanx> inspects the input and chooses the label appropriately, based on the OpenPGP packets encountered.</t>

<t><spanx style="verb">sop armor</spanx> ought to be able to correctly re-armor any of the packet streams that are produced by <spanx style="verb">sop</spanx> with the <spanx style="verb">--no-armor</spanx> option.</t>

<t>For example, if the type of the first OpenPGP packet is:</t>

<t><list style="symbols">
  <t><spanx style="verb">0x05</spanx> (Secret-Key), the packet stream should be parsed as a <spanx style="verb">KEYS</spanx> input (with Armor Header <spanx style="verb">BEGIN PGP PRIVATE KEY BLOCK</spanx>).</t>
  <t><spanx style="verb">0x06</spanx> (Public-Key), the packet stream should be parsed as a <spanx style="verb">CERTS</spanx> input (with Armor Header <spanx style="verb">BEGIN PGP PUBLIC KEY BLOCK</spanx>).</t>
  <t><spanx style="verb">0x01</spanx> (Public-key Encrypted Session Key) or <spanx style="verb">0x03</spanx> (Symmetric-key Encrypted Session Key), the packet stream should be parsed as a <spanx style="verb">CIPHERTEXT</spanx> input (with Armor Header <spanx style="verb">BEGIN PGP MESSAGE</spanx>).</t>
  <t><spanx style="verb">0x04</spanx> (One-Pass Signature), the packet stream should be parsed as an <spanx style="verb">INLINESIGNED</spanx> input (with Armor Header <spanx style="verb">BEGIN PGP MESSAGE</spanx>).</t>
  <t><spanx style="verb">0x02</spanx> (Signature), the packet stream may be either a <spanx style="verb">SIGNATURES</spanx> input or an <spanx style="verb">INLINESIGNED</spanx> input.
If the packet stream contains only Signature packets, it should be parsed as a <spanx style="verb">SIGNATURES</spanx> input (with Armor Header <spanx style="verb">BEGIN PGP SIGNATURE</spanx>).
If it contains any packet other than a Signature packet, it should be parsed as an <spanx style="verb">INLINESIGNED</spanx> input (with Armor Header <spanx style="verb">BEGIN PGP MESSAGE</spanx>).</t>
</list></t>

<t>If the input packet stream does not match any expected sequence of packet types, <spanx style="verb">sop armor</spanx> fails with <spanx style="verb">BAD_DATA</spanx>.</t>

<t>Since <spanx style="verb">sop armor</spanx> accepts ASCII-armored input as well as binary input, this operation is idempotent on well-structured data.
A caller can use this subcommand blindly to ensure that any well-formed OpenPGP packet stream is 7-bit clean.</t>

<t>FIXME: what to do if the input is a CSF <spanx style="verb">INLINESIGNED</spanx> message?
Three choices:</t>

<t><list style="symbols">
  <t>Leave it untouched -- this violates the claim about blindly ensuring 7-bit clean, since UTF-8-encoded message text is not necessarily 7-bit clean.</t>
  <t>Convert to ASCII-armored <spanx style="verb">INLINESIGNED</spanx> -- this requires synthesis of OPS packet (from signatures block) and Literal Data packet (from the message body).</t>
  <t>Raise a specific error.</t>
</list></t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop armor < bob.cert.bin > bob.cert
$ head -n1 bob.cert
-----BEGIN PGP PUBLIC KEY BLOCK-----
$
]]></artwork></figure>

<section anchor="historic-options-for-sop-armor"><name>Historic Options for sop armor</name>

<t><spanx style="verb">sop armor</spanx> used to be specified as having a <spanx style="verb">--label</spanx> option, with an argument that took one of the following values: <spanx style="verb">auto</spanx>, <spanx style="verb">sig</spanx>, <spanx style="verb">key</spanx>, <spanx style="verb">cert</spanx>, or <spanx style="verb">message</spanx>, which allowed the user to specify the label used in the header and tail of the armoring.</t>

<t>The default value for <spanx style="verb">--label</spanx> was <spanx style="verb">auto</spanx>, which matches the currently specified behavior.
This option is now deprecated, as it offers no useful functionality.</t>

</section>
</section>
<section anchor="dearmor-convert-ascii-to-binary"><name>dearmor: Convert ASCII to Binary</name>

<figure><artwork><![CDATA[
sop dearmor
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: OpenPGP material (<spanx style="verb">SIGNATURES</spanx>, <spanx style="verb">KEYS</spanx>, <spanx style="verb">CERTS</spanx>, <spanx style="verb">CIPHERTEXT</spanx>, or <spanx style="verb">INLINESIGNED</spanx>)</t>
  <t>Standard Output: the same material with any ASCII-armoring removed</t>
</list></t>

<t>If the input packet stream does not match any of the expected sequence of packet types, <spanx style="verb">sop dearmor</spanx> fails with <spanx style="verb">BAD_DATA</spanx>.  See also <xref target="optional-input-armoring"/>.</t>

<t>Since <spanx style="verb">sop dearmor</spanx> accepts binary-formatted input as well as ASCII-armored input, this operation is idempotent on well-structured data.
A caller can use this subcommand blindly ensure that any well-formed OpenPGP packet stream is in its standard binary representation.</t>

<t>FIXME: what to do if the input is a CSF <spanx style="verb">INLINESIGNED</spanx>?
Three choices:</t>

<t><list style="symbols">
  <t>Leave it untouched -- output data is not really in binary format.</t>
  <t>Convert to binary-format <spanx style="verb">INLINESIGNED</spanx> -- this requires synthesis of OPS packet (from CSF <spanx style="verb">Hash</spanx> header) and Literal Data packet (from the message body).</t>
  <t>Raise a specific error.</t>
</list></t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop dearmor < message.txt.asc > message.txt.sig
$
]]></artwork></figure>

</section>
</section>
</section>
<section anchor="input-string-types"><name>Input String Types</name>

<t>Some material is passed to <spanx style="verb">sop</spanx> directly as a string on the command line.</t>

<section anchor="date"><name>DATE</name>

<t>An ISO-8601 formatted timestamp with time zone, or the special value <spanx style="verb">now</spanx> to indicate the current system time.</t>

<t>Examples:</t>

<t><list style="symbols">
  <t><spanx style="verb">now</spanx></t>
  <t><spanx style="verb">2019-10-29T12:11:04+00:00</spanx></t>
  <t><spanx style="verb">2019-10-24T23:48:29Z</spanx></t>
  <t><spanx style="verb">20191029T121104Z</spanx></t>
</list></t>

<t>In some cases where used to specify lower and upper boundaries, a <spanx style="verb">DATE</spanx> value can be set to <spanx style="verb">-</spanx> to indicate "no time limit".</t>

<t>A flexible implementation of <spanx style="verb">sop</spanx> <bcp14>MAY</bcp14> accept date inputs in other unambiguous forms.</t>

<t>Note that whenever <spanx style="verb">sop</spanx> emits a timestamp (e.g., in <xref target="verifications"/>) it <bcp14>MUST</bcp14> produce only a UTC-based ISO-8601 compliant representation with a resolution of one second, using the literal <spanx style="verb">Z</spanx> suffix to indicate timezone.</t>

</section>
<section anchor="userid"><name>USERID</name>

<t>This is an arbitrary <spanx style="verb">UTF-8</spanx> string (<xref target="utf8"/>).
By convention, most User IDs are of the form <spanx style="verb">Display Name &lt;email.address@example.com&gt;</spanx>, but they do not need to be.</t>

<t>By internal policy, an implementation <bcp14>MAY</bcp14> reject a <spanx style="verb">USERID</spanx> if there are certain <spanx style="verb">UTF-8</spanx> strings it declines to work with as a User ID.
For example, an implementation may reject the empty string, or a string with characters in it that it considers problematic.
Of course, refusing to create a particular User ID does not prevent an implementation from encountering such a User ID in its input.</t>

</section>
<section anchor="subcommand"><name>SUBCOMMAND</name>

<t>This is an <spanx style="verb">ASCII</spanx> string that matches the name of one of the subcommands listed in <xref target="subcommands"/>.</t>

</section>
<section anchor="profile"><name>PROFILE</name>

<t>Some <spanx style="verb">sop</spanx> subcommands can accept a <spanx style="verb">--profile</spanx> option, which takes as an argument the name of a profile.</t>

<t>A profile name is a UTF-8 string that has no whitespace in it.</t>

<t>Which profiles are available depends on the <spanx style="verb">sop</spanx> implementation.</t>

<t>Similar to OpenPGP Notation names, profile names are divided into two namespaces: the IETF namespace and the user namespace.
A profile name in the user namespace ends with the <spanx style="verb">@</spanx> character (0x40) followed by a DNS domain name.
A profile name in the IETF namespace does not have an <spanx style="verb">@</spanx> character.</t>

<t>A profile name in the user space is owned and controlled by the owner of the domain in the suffix.
A <spanx style="verb">sop</spanx> implementation that implements a user profile but does not own the domain in question <bcp14>SHOULD</bcp14> hew as closely as possible to the semantics described by the owner of the domain.</t>

<t>A profile name in the IETF namespace that begins with the string <spanx style="verb">rfc</spanx> should have semantics that hew as closely as possible to the referenced RFC.
Similarly, a profile name in the IETF namespace that begins with the string <spanx style="verb">draft-</spanx> should have semantics that hew as closely as possible to the referenced Internet Draft.</t>

<t>The reserved profile name <spanx style="verb">default</spanx> in the IETF namespace simply refers to the implementation's default choices.
It is not mandatory to name the default profile <spanx style="verb">default</spanx>.
The first profile listed in the <spanx style="verb">list-profiles</spanx> output is considered the default configuration, as specified in <xref target="profilelist"/>.</t>

<t>The reserved profile names <spanx style="verb">security</spanx>, <spanx style="verb">performance</spanx>, and <spanx style="verb">compatibility</spanx> refer to the implementation's choices when increased emphasis on security, performance or compatibility is required, respectively.
It is not mandatory to name any profile <spanx style="verb">security</spanx>, <spanx style="verb">performance</spanx>, or <spanx style="verb">compatibility</spanx>; in that case, those profile names <bcp14>MUST</bcp14> act as aliases of another profile name.
They are also allowed to be aliases of the default profile.</t>

<t>Note that this profile mechanism is intended to provide a limited way for an implementation to select among a small set of options that the implementer has vetted and is satisfied with.
It is not intended to provide an arbitrary channel for complex configuration, and a <spanx style="verb">sop</spanx> implementation <bcp14>MUST NOT</bcp14> use it in that way.</t>

</section>
</section>
<section anchor="indirect-types"><name>Input/Output Indirect Types</name>

<t>Some material is passed to <spanx style="verb">sop</spanx> indirectly, typically by referring to a filename containing the data in question.
This type of data may also be passed to <spanx style="verb">sop</spanx> on Standard Input, or delivered by <spanx style="verb">sop</spanx> to Standard Output.</t>

<t>If any input data is specified explicitly to be read from a file that does not exist, <spanx style="verb">sop</spanx> will fail with <spanx style="verb">MISSING_INPUT</spanx>.</t>

<t>If any input data does not meet the requirements described below, <spanx style="verb">sop</spanx> will fail with <spanx style="verb">BAD_DATA</spanx>.</t>

<section anchor="special-designators"><name>Special Designators for Indirect Types</name>

<t>An indirect argument or parameter that starts with <u>@</u> is not treated as a filename, but is reserved for special handling, based on the prefix that follows the <spanx style="verb">@</spanx>.
We describe two of those prefixes (<spanx style="verb">@ENV:</spanx> and <spanx style="verb">@FD:</spanx>) here.
A <spanx style="verb">sop</spanx> implementation that receives such a special designator but does not know how to handle a given prefix in that context <bcp14>MUST</bcp14> fail with <spanx style="verb">UNSUPPORTED_SPECIAL_PREFIX</spanx>.</t>

<t>See <xref target="special-designators-guidance"/> for more details about safe handling of these special designators.</t>

<section anchor="env-special-designator-for-environment-variable"><name>@ENV: Special Designator for Environment Variable</name>

<t>If the filename for any indirect material used as input has the special form <spanx style="verb">@ENV:xxx</spanx>,
then contents of environment variable <spanx style="verb">$xxx</spanx> is used instead of looking in the filesystem.
<spanx style="verb">@ENV</spanx> is for input only: if the prefix <spanx style="verb">@ENV:</spanx> is used for any output argument, <spanx style="verb">sop</spanx> fails with <spanx style="verb">UNSUPPORTED_SPECIAL_PREFIX</spanx>.</t>

<t>The <spanx style="verb">sopv</spanx> subset (see <xref target="sopv"/>) <bcp14>MUST</bcp14> be capable of supporting the <spanx style="verb">@ENV</spanx> special designator for all relevant inputs starting at <spanx style="verb">sopv</spanx> version 1.0.</t>

</section>
<section anchor="fd-special-designator-for-file-descriptor"><name>@FD: Special Designator for File Descriptor</name>

<t>If the filename for any indirect material used as either input or output has the special form <spanx style="verb">@FD:nnn</spanx> where <spanx style="verb">nnn</spanx> is a decimal integer,
then the associated data is read from file descriptor <spanx style="verb">nnn</spanx>.</t>

<t>On platforms which support file descriptors, the <spanx style="verb">sopv</spanx> subset (see <xref target="sopv"/>) <bcp14>MUST</bcp14> be capable of supporting the <spanx style="verb">@FD</spanx> special designator for all relevant inputs and outputs starting at <spanx style="verb">sopv</spanx> version 1.0.</t>

</section>
</section>
<section anchor="certs"><name>CERTS</name>

<t>One or more OpenPGP certificates (<xref section="10.1" sectionFormat="of" target="RFC9580"/>), aka "Transferable Public Key".
May be armored (see <xref target="optional-input-armoring"/>).</t>

<t>Although some existing workflows may prefer to use one <spanx style="verb">CERTS</spanx> object with multiple certificates in it (a "keyring"), supplying exactly one certificate per <spanx style="verb">CERTS</spanx> input will make error reporting clearer and easier.</t>

<t>If any <spanx style="verb">CERTS</spanx> input contains secret key material, <spanx style="verb">sop</spanx> <bcp14>MUST</bcp14> fail with <spanx style="verb">BAD_DATA</spanx>.
This strictness is intended to keep the consumer of the <spanx style="verb">sop</spanx> interface clear about what material they are dealing with in what locations.
This should reduce the consumer's risk of accidentally exposing secret key material where they meant to expose a <spanx style="verb">CERTS</spanx> object.</t>

</section>
<section anchor="keys"><name>KEYS</name>

<t>One or more OpenPGP Transferable Secret Keys (<xref section="10.2" sectionFormat="of" target="RFC9580"/>).
May be armored (see <xref target="optional-input-armoring"/>).</t>

<t>Secret key material is often locked with a password to ensure that it cannot be simply copied and reused.
If any secret key material is locked with a password and no <spanx style="verb">--with-key-password</spanx> option is supplied, <spanx style="verb">sop</spanx> may fail with error <spanx style="verb">KEY_IS_PROTECTED</spanx>.
However, when a cleartext secret key (that is, one not locked with a password) is available, <spanx style="verb">sop</spanx> should always be able to use it, whether a <spanx style="verb">--with-key-password</spanx> option is supplied or not.</t>

<t>Although some existing workflows may prefer to use one <spanx style="verb">KEYS</spanx> object with multiple keys in it (a "secret keyring"), supplying exactly one key per <spanx style="verb">KEYS</spanx> input will make error reporting clearer and easier.</t>

</section>
<section anchor="ciphertext"><name>CIPHERTEXT</name>

<t><spanx style="verb">sop</spanx> accepts only a restricted subset of the arbitrarily-nested grammar allowed by the OpenPGP Messages definition (<xref section="10.3" sectionFormat="of" target="RFC9580"/>).</t>

<t>In particular, it accepts and generates only:</t>

<t>An OpenPGP message, consisting of a sequence of PKESKs (<xref section="5.1" sectionFormat="of" target="RFC9580"/>) and SKESKs (<xref section="5.3" sectionFormat="of" target="RFC9580"/>),
followed by one SEIPD (<xref section="5.13" sectionFormat="of" target="RFC9580"/>).</t>

<t>The SEIPD can decrypt into one of two things:</t>

<t><list style="symbols">
  <t>"Maybe Signed Data" (see below), or</t>
  <t>Compressed data packet that contains "Maybe Signed Data"</t>
</list></t>

<t>"Maybe Signed Data" is a sequence of:</t>

<t><list style="symbols">
  <t>N (zero or more) one-pass signature packets, followed by</t>
  <t>zero or more signature packets, followed by</t>
  <t>one Literal data packet, followed by</t>
  <t>N signature packets (corresponding to the outer one-pass signatures packets)</t>
</list></t>

<t>FIXME: does any tool do compression inside signing?  Do we need to handle that?</t>

<t>May be armored (see <xref target="optional-input-armoring"/>).</t>

</section>
<section anchor="inlinesigned"><name>INLINESIGNED</name>

<t>An inline-signed message may take any one of three different forms:</t>

<t><list style="symbols">
  <t>A binary sequence of OpenPGP packets that matches a subset of the "Signed Message" element in the grammar in <xref section="10.3" sectionFormat="of" target="RFC9580"/></t>
  <t>The same sequence of packets, but ASCII-armored (see <xref target="optional-input-armoring"/>)</t>
  <t>A message using the Cleartext Signature Framework described in <xref section="7" sectionFormat="of" target="RFC9580"/></t>
</list></t>

<t>The subset of the packet grammar expected in the first two forms consists of either:</t>

<t><list style="symbols">
  <t>a series of Signature packets followed by a Literal Data packet</t>
  <t>a series of One-Pass Signature (OPS) packets, followed by one Literal Data packet, followed by an equal number of Signature packets corresponding to the OPS packets</t>
</list></t>

<t>When the message is in the third form (Cleartext Signature Framework), it has the following properties:</t>

<t><list style="symbols">
  <t>The stream <bcp14>SHOULD</bcp14> consist solely of <spanx style="verb">UTF-8</spanx> text</t>
  <t>Every Signature packet found in the stream <bcp14>SHOULD</bcp14> have Signature Type 0x01 (canonical text document).</t>
  <t>It <bcp14>SHOULD NOT</bcp14> contain leading text (before the <spanx style="verb">-----BEGIN PGP SIGNED MESSAGE-----</spanx> cleartext header) or trailing text (after the <spanx style="verb">-----END PGP SIGNATURE-----</spanx> armor tail).</t>
</list></t>

<t>While some OpenPGP implementations <bcp14>MAY</bcp14> produce more complicated inline signed messages, a <spanx style="verb">sop</spanx> implementation <bcp14>SHOULD</bcp14> limit itself to producing these straightforward forms.</t>

</section>
<section anchor="signature"><name>SIGNATURES</name>

<t>One or more OpenPGP Signature packets.  May be armored (see <xref target="optional-input-armoring"/>).</t>

</section>
<section anchor="sessionkey"><name>SESSIONKEY</name>

<t>This documentation uses the GnuPG defacto <spanx style="verb">ASCII</spanx> representation:</t>

<t><spanx style="verb">ALGONUM:HEXKEY</spanx></t>

<t>where <spanx style="verb">ALGONUM</spanx> is the decimal value associated with the OpenPGP Symmetric Key Algorithms (<xref section="9.3" sectionFormat="of" target="RFC9580"/>) and <spanx style="verb">HEXKEY</spanx> is the hexadecimal
representation of the binary key.</t>

<t>Example AES-256 session key:</t>

<figure><artwork><![CDATA[
9:FCA4BEAF687F48059CACC14FB019125CD57392BAB7037C707835925CBF9F7BCD
]]></artwork></figure>

<t>A <spanx style="verb">sop</spanx> implementation <bcp14>SHOULD</bcp14> produce session key data in this format, with a trailing newline.
When consuming such a session key, <spanx style="verb">sop</spanx> <bcp14>SHOULD</bcp14> be willing to accept either upper or lower case hexadecimal digits, and to gracefully ignore any trailing whitespace.</t>

</section>
<section anchor="micalg"><name>MICALG</name>

<t>This output-only type indicates the cryptographic digest used when making a signature.
It is useful specifically when generating signed PGP/MIME objects, which want a <spanx style="verb">micalg=</spanx> parameter for the <spanx style="verb">multipart/signed</spanx> content type as described in <xref section="5" sectionFormat="of" target="RFC3156"/>.</t>

<t>It will typically be a string like <spanx style="verb">pgp-sha512</spanx>, but in some situations (multiple signatures using different digests) it will be the empty string.
If the user of <spanx style="verb">sop</spanx> is assembling a PGP/MIME signed object, and the <spanx style="verb">MICALG</spanx> output is the empty string,
the user should omit the <spanx style="verb">micalg=</spanx> parameter entirely.</t>

</section>
<section anchor="password"><name>PASSWORD</name>

<t>This input-only is expected to be a <spanx style="verb">UTF-8</spanx> string (<xref target="utf8"/>), but for <spanx style="verb">sop decrypt</spanx>, any bytestring that the user supplies will be accepted.
Note the details in <spanx style="verb">sop encrypt</spanx> and <spanx style="verb">sop decrypt</spanx> about trailing whitespace!</t>

<t>See also <xref target="human-readable-passwords"/> for more discussion.</t>

</section>
<section anchor="verifications"><name>VERIFICATIONS</name>

<t>This output-only type consists of one line per successful signature verification.
Each line has four structured fields delimited by a single space,
followed by a single-line JSON object or arbitrary text to the end of the line.</t>

<t><list style="symbols">
  <t>ISO-8601 UTC datestamp of the signature, to one second precision, using the <spanx style="verb">Z</spanx> suffix</t>
  <t>Fingerprint of the signing component key</t>
  <t>Fingerprint of primary key of signing certificate (if signed by primary key, same as the previous field)</t>
  <t>A string describing the mode of the signature, either <spanx style="verb">mode:text</spanx> or <spanx style="verb">mode:binary</spanx></t>
  <t>A JSON object or free-form message describing the verification (see <xref target="verifications-json"/>)</t>
</list></t>

<t>Note that while <xref target="date"/> permits a <spanx style="verb">sop</spanx> implementation to accept other unambiguous date representations,
its date output here <bcp14>MUST</bcp14> be a strict ISO-8601 UTC date timestamp.
In particular:</t>

<t><list style="symbols">
  <t>the date and time fields <bcp14>MUST</bcp14> be separated by <spanx style="verb">T</spanx>, not by whitespace, since whitespace is used as a delimiter</t>
  <t>the time <bcp14>MUST</bcp14> be emitted in UTC, with the explicit suffix <spanx style="verb">Z</spanx></t>
  <t>the time <bcp14>MUST</bcp14> be emitted with one-second precision</t>
</list></t>

<t>Example:</t>

<figure><artwork><![CDATA[
2019-10-24T23:48:29Z C90E6D36200A1B922A1509E77618196529AE5FF8 C4BC2DDB38CCE96485EBE9C2F20691179038E5C6 mode:binary {"signers": ["dkg.asc"]}
]]></artwork></figure>

<section anchor="verifications-json"><name>VERIFICATIONS extension JSON</name>

<t>The final field of each <spanx style="verb">VERIFICATIONS</spanx> line is either JSON data or arbitrary text.</t>

<t>If the final field begins and ends with curly brackets (<u>{</u> and <u>}</u>, it is JSON data.
Otherwise, the final field is arbitrary text (whose content and structure are up to the discretion of the implementation).</t>

<t>JSON data allows for sophisticated future extensions, and is the preferred form of this field.
Arbitrary text is deprecated.
The rest of this subsection describes the JSON data.</t>

<t>The JSON data is a single JSON object, coerced into a one-line representation (there are no literal LINE FEED (U+000A) characters in it, though there may be appropriately escaped LINE FEED characters within the JSON text).</t>

<t>The JSON object <bcp14>MAY</bcp14> contain the following keys:</t>

<t><list style="symbols">
  <t><spanx style="verb">signers</spanx>: a list of the supplied <spanx style="verb">CERTS</spanx> objects that could have issued the signature, identified by the name given on the command line.
If this key is present, as long as any OpenPGP certificate in a given <spanx style="verb">CERTS</spanx> object could have issued the signature, that <spanx style="verb">CERTS</spanx> object <bcp14>MUST</bcp14> be listed here.
If multiple <spanx style="verb">CERTS</spanx> objects contain certificates that could have issued the signature, each <spanx style="verb">CERTS</spanx> <bcp14>MUST</bcp14> be listed here.</t>
  <t><spanx style="verb">comment</spanx>: Free-form UTF-8-encoded text describing the verification.
An internationalized, locale-aware <spanx style="verb">sop</spanx> implementation should localize this field.</t>
  <t><spanx style="verb">ext</spanx>: A "extensions" JSON object containing arbitrary, implementation-specific data.</t>
</list></t>

<t>To avoid collisions with future definitions, the top-level JSON object <bcp14>MUST NOT</bcp14> contain any other keys.
For forward compatibility, when consuming a JSON object produced by a SOP implementation, unknown keys <bcp14>MUST</bcp14> be ignored.</t>

</section>
</section>
<section anchor="data"><name>DATA</name>

<t>Cleartext, arbitrary data.  This is either a bytestream or <spanx style="verb">UTF-8</spanx> text.</t>

<t>It <bcp14>MUST</bcp14> only be <spanx style="verb">UTF-8</spanx> text in the case of input supplied to <spanx style="verb">sop sign --as=text</spanx> or <spanx style="verb">sop encrypt --as=text</spanx>.
If <spanx style="verb">sop</spanx> receives <spanx style="verb">DATA</spanx> containing non-<spanx style="verb">UTF-8</spanx> octets in this case, it will fail (see <xref target="utf8"/>) with <spanx style="verb">EXPECTED_TEXT</spanx>.</t>

</section>
<section anchor="profilelist"><name>PROFILELIST</name>

<t>This output-only type consists of simple UTF-8 textual output, with one line per profile.
Each line consists of the profile name optionally followed by a colon (0x31), a space (0x20), and a brief human-readable description of the intended semantics of the profile.
Each line may be at most 1000 bytes, and no more than 4 profiles may be listed.</t>

<t>These limits are intended to force <spanx style="verb">sop</spanx> implementers to make hard decisions and to keep things simple.</t>

<t>The first profile <bcp14>MAY</bcp14> be explicitly named <spanx style="verb">default</spanx>.
If it is not named <spanx style="verb">default</spanx>, then <spanx style="verb">default</spanx> is an alias for the first profile listed.
No profile after the first listed may be named <spanx style="verb">default</spanx>.</t>

<t>Any of the profiles <bcp14>MAY</bcp14> be explicitly named <spanx style="verb">security</spanx>, <spanx style="verb">performance</spanx>, or <spanx style="verb">compatibility</spanx>.
If none of the listed profiles have (some of) these names, the profiles of which they are an alias should indicate as much in the human-readable description.</t>

<t>See <xref target="profile"/> for more discussion about the namespace and intended semantics of each profile.</t>

</section>
</section>
<section anchor="failure-modes"><name>Failure Modes</name>

<t><spanx style="verb">sop</spanx> return codes have both mnemonics and numeric values.</t>

<t>When <spanx style="verb">sop</spanx> succeeds, it will return 0 (<spanx style="verb">OK</spanx>) and emit nothing to Standard Error.
When <spanx style="verb">sop</spanx> fails, it fails with a non-zero return code, and emits one or more warning messages on Standard Error.
Known return codes include:</t>

<texttable title="Error return codes">
      <ttcol align='right'>Value</ttcol>
      <ttcol align='left'>Mnemonic</ttcol>
      <ttcol align='left'>Meaning</ttcol>
      <c>0</c>
      <c><spanx style="verb">OK</spanx></c>
      <c>Success</c>
      <c>1</c>
      <c><spanx style="verb">UNSPECIFIED_FAILURE</spanx></c>
      <c>An otherwise unspecified failure occurred</c>
      <c>3</c>
      <c><spanx style="verb">NO_SIGNATURE</spanx></c>
      <c>No acceptable signatures found (<spanx style="verb">sop verify</spanx>)</c>
      <c>13</c>
      <c><spanx style="verb">UNSUPPORTED_ASYMMETRIC_ALGO</spanx></c>
      <c>Asymmetric algorithm unsupported (<spanx style="verb">sop encrypt</spanx>)</c>
      <c>17</c>
      <c><spanx style="verb">CERT_CANNOT_ENCRYPT</spanx></c>
      <c>Certificate not encryption-capable (e.g., expired, revoked, unacceptable usage flags) (<spanx style="verb">sop encrypt</spanx>)</c>
      <c>19</c>
      <c><spanx style="verb">MISSING_ARG</spanx></c>
      <c>Missing required argument</c>
      <c>23</c>
      <c><spanx style="verb">INCOMPLETE_VERIFICATION</spanx></c>
      <c>Incomplete verification instructions (<spanx style="verb">sop decrypt</spanx>)</c>
      <c>29</c>
      <c><spanx style="verb">CANNOT_DECRYPT</spanx></c>
      <c>Unable to decrypt (<spanx style="verb">sop decrypt</spanx>)</c>
      <c>31</c>
      <c><spanx style="verb">PASSWORD_NOT_HUMAN_READABLE</spanx></c>
      <c>Non-<spanx style="verb">UTF-8</spanx> or otherwise unreliable password (<spanx style="verb">sop encrypt</spanx>, <spanx style="verb">sop generate-key</spanx>)</c>
      <c>37</c>
      <c><spanx style="verb">UNSUPPORTED_OPTION</spanx></c>
      <c>Unsupported option</c>
      <c>41</c>
      <c><spanx style="verb">BAD_DATA</spanx></c>
      <c>Invalid data type (no secret key where <spanx style="verb">KEYS</spanx> expected, secret key where <spanx style="verb">CERTS</spanx> expected, etc)</c>
      <c>53</c>
      <c><spanx style="verb">EXPECTED_TEXT</spanx></c>
      <c>Non-text input where text expected</c>
      <c>59</c>
      <c><spanx style="verb">OUTPUT_EXISTS</spanx></c>
      <c>Output file already exists</c>
      <c>61</c>
      <c><spanx style="verb">MISSING_INPUT</spanx></c>
      <c>Input file does not exist</c>
      <c>67</c>
      <c><spanx style="verb">KEY_IS_PROTECTED</spanx></c>
      <c>A <spanx style="verb">KEYS</spanx> input is password-protected (locked), and <spanx style="verb">sop</spanx> cannot unlock it with any of the <spanx style="verb">--with-key-password</spanx> (or <spanx style="verb">--old-key-password</spanx>) options</c>
      <c>69</c>
      <c><spanx style="verb">UNSUPPORTED_SUBCOMMAND</spanx></c>
      <c>Unsupported subcommand</c>
      <c>71</c>
      <c><spanx style="verb">UNSUPPORTED_SPECIAL_PREFIX</spanx></c>
      <c>An indirect parameter is a special designator (it starts with <spanx style="verb">@</spanx>) but <spanx style="verb">sop</spanx> does not know how to handle the prefix</c>
      <c>73</c>
      <c><spanx style="verb">AMBIGUOUS_INPUT</spanx></c>
      <c>A indirect input parameter is a special designator (it starts with <spanx style="verb">@</spanx>), and a filename matching the designator is actually present</c>
      <c>79</c>
      <c><spanx style="verb">KEY_CANNOT_SIGN</spanx></c>
      <c>Key not signature-capable (e.g., expired, revoked, unacceptable usage flags) (<spanx style="verb">sop sign</spanx> and <spanx style="verb">sop encrypt</spanx> with <spanx style="verb">--sign-with</spanx>)</c>
      <c>83</c>
      <c><spanx style="verb">INCOMPATIBLE_OPTIONS</spanx></c>
      <c>Options were supplied that are incompatible with each other</c>
      <c>89</c>
      <c><spanx style="verb">UNSUPPORTED_PROFILE</spanx></c>
      <c>The requested profile is unsupported (<spanx style="verb">sop generate-key</spanx>, <spanx style="verb">sop encrypt</spanx>), or the indicated subcommand does not accept profiles (<spanx style="verb">sop list-profiles</spanx>)</c>
      <c>97</c>
      <c><spanx style="verb">NO_HARDWARE_KEY_FOUND</spanx></c>
      <c>The <spanx style="verb">sop</spanx> implementation  supports some form of hardware-backed secret keys, but could not identify the hardware device (see <xref target="hardware-backed-secrets"/>)</c>
      <c>101</c>
      <c><spanx style="verb">HARDWARE_KEY_FAILURE</spanx></c>
      <c>The <spanx style="verb">sop</spanx> implementation tried to use a hardware-backed secret key, but the cryptographic hardware refused the operation for some reason other than a bad PIN or password (see <xref target="hardware-backed-secrets"/>)</c>
      <c>103</c>
      <c><spanx style="verb">PRIMARY_KEY_BAD</spanx></c>
      <c>The primary key of a <spanx style="verb">KEYS</spanx> object is too weak or revoked</c>
      <c>107</c>
      <c><spanx style="verb">CERT_USERID_NO_MATCH</spanx></c>
      <c>The <spanx style="verb">CERTS</spanx> object has no matching User ID</c>
      <c>109</c>
      <c><spanx style="verb">KEY_CANNOT_CERTIFY</spanx></c>
      <c>Key not certification-capable (e.g., expired, revoked, unacceptable usage flags) (<spanx style="verb">sop certify-userid</spanx>)</c>
</texttable>

<t>If a <spanx style="verb">sop</spanx> implementation fails in some way not contemplated by this document, it <bcp14>MAY</bcp14> return <spanx style="verb">UNSPECIFIED_FAILURE</spanx> or any non-zero error code, not only those listed above.</t>

</section>
<section anchor="known-implementations"><name>Known Implementations</name>

<t>The following implementations are known at the time of this draft:</t>

<texttable title="Known implementations">
      <ttcol align='left'>Project name</ttcol>
      <ttcol align='left'>cli name</ttcol>
      <ttcol align='left'>notes</ttcol>
      <c>dkg-sop</c>
      <c><spanx style="verb">dkg-sop</spanx></c>
      <c>Implemented in C++ using the LibTMCG library (<xref target="DKG-SOP"/>)</c>
      <c>gosop</c>
      <c><spanx style="verb">gosop</spanx></c>
      <c>Implemented in golang (Go) using GOpenPGP (<xref target="GOSOP"/>)</c>
      <c>gpgme-sop</c>
      <c><spanx style="verb">gpgme-sop</spanx></c>
      <c>A Rust wrapper around the gpgme C library (<xref target="GPGME-SOP"/>)</c>
      <c>minipgp6-sop</c>
      <c><spanx style="verb">msop</spanx></c>
      <c>Implemented in Rust based on <spanx style="verb">minipgp6</spanx> (<xref target="MSOP"/>)</c>
      <c>PGPainless SOP</c>
      <c><spanx style="verb">pgpainless-cli</spanx></c>
      <c>Implemented in Java using PGPainless (<xref target="PGPAINLESS-CLI"/>)</c>
      <c>RNP-sop</c>
      <c><spanx style="verb">rnp-sop</spanx></c>
      <c>A Rust wrapper around the librnp C library (<xref target="RNP-SOP"/>)</c>
      <c>rsop</c>
      <c><spanx style="verb">rsop</spanx></c>
      <c>Implemented in Rust using the <spanx style="verb">rpgpie</spanx> crate (<xref target="RSOP"/>)</c>
      <c>Sequoia SOP</c>
      <c><spanx style="verb">sqop</spanx></c>
      <c>Implemented in Rust using the <spanx style="verb">sequoia-openpgp</spanx> crate (<xref target="SQOP"/>)</c>
      <c>sop-openpgp.js</c>
      <c><spanx style="verb">sop-openpgp.js</spanx></c>
      <c>Implemented in JavaScript using OpenPGP.js (<xref target="SOP-OPENPGPJS"/>)</c>
      <c>sopgpy</c>
      <c><spanx style="verb">sopgpy</spanx></c>
      <c>Implemented in Python using PGPy (<xref target="SOPGPY"/>)</c>
</texttable>

</section>
<section anchor="alternate-interfaces"><name>Alternate Interfaces</name>

<t>This draft primarily defines a command line interface, but future versions may try to outline a comparable idiomatic interface for C or some other widely-used programming language.</t>

<t>Comparable idiomatic interfaces are already active in the wild for different programming languages, in particular:</t>

<t><list style="symbols">
  <t>Rust: <xref target="RUST-SOP"/></t>
  <t>Java: <xref target="SOP-JAVA"/></t>
  <t>Python: <xref target="PYTHON-SOP"/></t>
</list></t>

<t>These programmatic interfaces are typically coupled with a wrapper that can automatically generate a command-line tool compatible with this draft.</t>

<t>An implementation that uses one of these languages should target the corresponding idiomatic interface for ease of development and interoperability.</t>

</section>
<section anchor="guidance-for-implementers"><name>Guidance for Implementers</name>

<t><spanx style="verb">sop</spanx> uses a few assumptions that implementers might want to consider.</t>

<section anchor="one-openpgp-message-at-a-time"><name>One OpenPGP Message at a Time</name>

<t><spanx style="verb">sop</spanx> is intended to be a simple tool that operates on one OpenPGP object at a time.  It should be composable, if you want to use it to deal with multiple OpenPGP objects.</t>

<t>FIXME: discuss what this means for streaming.
The stdio interface doesn't necessarily imply streamed output.</t>

</section>
<section anchor="simplified-subset-of-openpgp-message"><name>Simplified Subset of OpenPGP Message</name>

<t>While the formal grammar for OpenPGP Message is arbitrarily nestable, <spanx style="verb">sop</spanx> constrains itself to what it sees as a single "layer" (see <xref target="ciphertext"/>).</t>

<t>This is a deliberate choice, because it is what most consumers expect.
Also, if an arbitrarily-nested structure is parsed with a recursive algorithm, this risks a denial of service vulnerability.
<spanx style="verb">sop</spanx> intends to be implementable with a parser that defensively declines to do recursive descent into an OpenPGP Message.</t>

<t>Note that an implementation of <spanx style="verb">sop decrypt</spanx> <bcp14>MAY</bcp14> choose to handle more complex structures, but if it does, it should document the other structures it handles and why it chooses to do so.
We can use such documentation to improve future versions of this spec.</t>

</section>
<section anchor="validate-signatures-only-from-known-signers"><name>Validate Signatures Only from Known Signers</name>

<t>There are generally only a few signers who are relevant for a given OpenPGP message.
When verifying signatures, <spanx style="verb">sop</spanx> expects that the caller can identify those relevant signers ahead of time.</t>

</section>
<section anchor="optional-input-armoring"><name>OpenPGP Inputs can be either Binary or ASCII-armored</name>

<t>OpenPGP material on input can be in either ASCII-armored or binary form.
This is a deliberate choice because there are typical scenarios where the program can't predict which form will appear.
Expecting the caller of <spanx style="verb">sop</spanx> to detect the form and adjust accordingly seems both redundant and error-prone.</t>

<t>The simple way to detect possible ASCII-armoring is to see whether the high bit of the first octet is set:
<xref section="4.2" sectionFormat="of" target="RFC9580"/> indicates that bit 7 is always one in the first octet of an OpenPGP packet.
In standard ASCII-armor, the first character is <u>-</u>, so the high bit should be cleared.</t>

<t>When considering an input as ASCII-armored OpenPGP material, <spanx style="verb">sop</spanx> <bcp14>MAY</bcp14> reject an input based on any of the following variations (see <xref section="6.2" sectionFormat="of" target="RFC9580"/> for precise definitions):</t>

<t><list style="symbols">
  <t>An unknown Armor Header Line</t>
  <t>Any text before the Armor Header Line</t>
  <t>Malformed lines in the Armor Headers section</t>
  <t>Any non-whitespace data after the Armor Tail</t>
  <t>Any Radix-64 encoded line with more than 76 characters</t>
  <t>Invalid characters in the Radix-64-encoded data</t>
  <t>An invalid Armor Checksum</t>
  <t>A mismatch between the Armor Header Line and the Armor Tail</t>
  <t>More than one ASCII-armored object in the input</t>
</list></t>

<t>For robustness, <spanx style="verb">sop</spanx> <bcp14>SHOULD</bcp14> be willing to ignore whitespace after the Armor Tail.</t>

<t>For any plural data type (i.e.,<spanx style="verb">SIGNATURES</spanx>, <spanx style="verb">CERTS</spanx>, or <spanx style="verb">KEYS</spanx>), the unarmored form is trivially concatenatable with another object of the same type (e.g., with Unix's <spanx style="verb">cat</spanx> utility).
But the armored forms are not concatenatable without first dearmoring.
To avoid inconsistent behavior, a <spanx style="verb">sop</spanx> implementation <bcp14>SHOULD</bcp14> reject anything that appears to be a concatenated series of ASCII-armored objects.</t>

<t>When considering OpenPGP material as input, regardless of whether it is ASCII-armored or binary, <spanx style="verb">sop</spanx> <bcp14>SHOULD</bcp14> reject any material that doesn't produce a valid stream of OpenPGP packets.
For example, <spanx style="verb">sop</spanx> <bcp14>SHOULD</bcp14> raise an error if an OpenPGP packet header is malformed, or if there is trailing garbage after the end of a packet.</t>

<t>For a given type of OpenPGP input material (i.e.,  <spanx style="verb">SIGNATURES</spanx>, <spanx style="verb">CERTS</spanx>, <spanx style="verb">KEYS</spanx>, <spanx style="verb">INLINESIGNED</spanx>, or <spanx style="verb">CIPHERTEXT</spanx>), <spanx style="verb">sop</spanx> <bcp14>SHOULD</bcp14> also reject any input that does not conform to the expected packet stream.
See <xref target="indirect-types"/> for the expected packet stream for different types.</t>

</section>
<section anchor="csf-risks"><name>Complexities of the Cleartext Signature Framework</name>

<t><spanx style="verb">sop</spanx> prefers a detached signature as the baseline form of OpenPGP signature, but provides affordances for dealing with inline-signed messages (see <spanx style="verb">INLINESIGNED</spanx>, <xref target="inlinesigned"/>) as well.</t>

<t>The most complex form of inline-signed messages is the Cleartext Signature Framework (CSF).
Handling the CSF structure requires parsing to delimit the multiple parts of the document, including at least:</t>

<t><list style="symbols">
  <t>any preamble before the message</t>
  <t>the inline message header (delimiter line, OpenPGP headers)</t>
  <t>the message itself</t>
  <t>the divider between the message and the signature (including any OpenPGP headers there)</t>
  <t>the signature</t>
  <t>the divider that terminates the signature</t>
  <t>any suffix after the signature</t>
</list></t>

<t>Note also that the preamble or the suffix might be arbitrary text, and might themselves contain OpenPGP messages (whether signatures or otherwise).</t>

<t>If the parser that does this split differs in any way from the parser that does the verification, or parts of the message are confused,
it would be possible to produce a verification status and an actual signed message that don't correspond to one another.</t>

<t>Blurred boundary problems like this can produce ugly attacks similar to those found in <xref target="EFAIL"></xref>.</t>

<t>A user of <spanx style="verb">sop</spanx> that receives an inline-signed message (whether the message uses the CSF or not) can detach the signature from the message with <spanx style="verb">sop inline-detach</spanx> (see <xref target="inline-detach"/>).</t>

<t>Alternately, the user can send the message through <spanx style="verb">sop inline-verify</spanx> to confirm required signatures, and then (if signatures are valid) supply its output to the consumer of the signed message.</t>

</section>
<section anchor="cert-validity-performance"><name>Reliance on Supplied Certs and Keys</name>

<t>A truly stateless implementation may find that it spends more time validating the internal consistency of certificates and keys than it does on the actual object security operations.</t>

<t>For performance reasons, an implementation may choose to ignore validation on certificate and key material supplied to it.  The security implications of doing so depend on how the certs and keys are managed outside of <spanx style="verb">sop</spanx>.</t>

</section>
<section anchor="utf8"><name>Text is always UTF-8</name>

<t>Various places in this specification require UTF-8 <xref target="RFC3629"/> when encoding text. <spanx style="verb">sop</spanx> implementations <bcp14>SHOULD NOT</bcp14> consider textual data in any other character encoding.</t>

<t>OpenPGP Implementations <bcp14>MUST</bcp14> already handle UTF-8, because various parts of <xref target="RFC9580"/> require it, including:</t>

<t><list style="symbols">
  <t>User ID</t>
  <t>Notation name</t>
  <t>Reason for revocation</t>
  <t>ASCII-armor Comment: header</t>
</list></t>

<t>Dealing with messages in other charsets leads to weird security failures like <xref target="Charset-Switching"/>, especially when the charset indication is not covered by any sort of cryptographic integrity check.
Restricting textual data to <spanx style="verb">UTF-8</spanx> universally across the OpenPGP ecosystem eliminates any such risk without losing functionality, since <spanx style="verb">UTF-8</spanx> can encode all known characters.</t>

</section>
<section anchor="human-readable-passwords"><name>Passwords are Human-Readable</name>

<t>Passwords are generally expected to be human-readable, as they are typically recorded and transmitted as human-visible, human-transferable strings.
However, they are used in the OpenPGP protocol as bytestrings, so it is important to ensure that there is a reliable bidirectional mapping between strings and bytes.
The maximally robust behavior here is for <spanx style="verb">sop encrypt</spanx> and <spanx style="verb">sop generate-key</spanx> (that is, commands that use a password to encrypt) to constrain the choice of passwords to strings that have such a mapping,
and for <spanx style="verb">sop decrypt</spanx> and <spanx style="verb">sop sign</spanx> (and <spanx style="verb">sop inline-sign</spanx>, as well as <spanx style="verb">sop encrypt</spanx> when decrypting a signing key; that is, commands that use a password to decrypt) to try multiple plausible versions of any password supplied by <spanx style="verb">PASSWORD</spanx>.</t>

<section anchor="generating-human-readable"><name>Generating Material with Human-Readable Passwords</name>

<t>When generating material based on a password, <spanx style="verb">sop encrypt</spanx> and <spanx style="verb">sop generate-key</spanx> enforce that the password is actually meaningfully human-transferable.
In particular, an implementation generating material based on a new password <bcp14>SHOULD</bcp14> apply the following considerations to the supplied password:</t>

<t><list style="symbols">
  <t>require <spanx style="verb">UTF-8</spanx></t>
  <t>trim trailing whitespace</t>
</list></t>

<t>Some <spanx style="verb">sop encrypt</spanx> and <spanx style="verb">sop generate-key</spanx> implementations may make even more strict requirements on input to ensure that they are transferable between humans in a robust way.</t>

<t>For example, a more strict <spanx style="verb">sop encrypt</spanx> or <spanx style="verb">sop generate-key</spanx> <bcp14>MAY</bcp14> also:</t>

<t><list style="symbols">
  <t>forbid leading whitespace</t>
  <t>forbid non-printing characters other than <spanx style="verb">SPACE (U+0020)</spanx>, such as <spanx style="verb">ZERO WIDTH NON-JOINER (U+200C)</spanx> or <spanx style="verb">TAB (U+0009)</spanx></t>
  <t>require the password to be in Unicode Normal Form C (<xref target="UNICODE-NORMALIZATION"/>)</t>
</list></t>

<t>Violations of these more-strict policies <bcp14>SHOULD</bcp14> result in an error of <spanx style="verb">PASSWORD_NOT_HUMAN_READABLE</spanx>.</t>

<t>A <spanx style="verb">sop encrypt</spanx> or <spanx style="verb">sop generate-key</spanx> implementation typically <bcp14>SHOULD NOT</bcp14> attempt enforce a minimum "password strength",
but in the event that some implementation does, it <bcp14>MUST NOT</bcp14> represent a weak password with <spanx style="verb">PASSWORD_NOT_HUMAN_READABLE</spanx>.</t>

</section>
<section anchor="consuming-passwords"><name>Consuming Password-protected Material</name>

<t>When <spanx style="verb">sop decrypt</spanx> receives a <spanx style="verb">PASSWORD</spanx> input, either from a <spanx style="verb">--with-key-password</spanx> or <spanx style="verb">--with-password</spanx> option, it sees its content as a bytestring.
<spanx style="verb">sop sign</spanx> also sees the content of any <spanx style="verb">PASSWORD</spanx> input supplied to its <spanx style="verb">--with-key-password</spanx>  option as a bytestring.
If the bytestring fails to work as a password, but ends in <spanx style="verb">UTF-8</spanx> whitespace, it will try again with the trailing whitespace removed.
This handles a common pattern of using a file with a final newline, for example.
The pattern here is one of robustness in the face of typical errors in human-transferred textual data.</t>

<t>A more robust <spanx style="verb">sop decrypt</spanx> or <spanx style="verb">sop sign</spanx> implementation that finds neither of the above two attempts work for a given <spanx style="verb">PASSWORD</spanx> <bcp14>MAY</bcp14> try additional variations if they produce a different bytestring, such as:</t>

<t><list style="symbols">
  <t>trimming any leading whitespace, if discovered</t>
  <t>trimming any internal non-printable characters other than <spanx style="verb">SPACE (U+0020)</spanx></t>
  <t>converting the supplied <spanx style="verb">PASSWORD</spanx> into Unicode Normal Form C (<xref target="UNICODE-NORMALIZATION"/>)</t>
</list></t>

<t>A <spanx style="verb">sop decrypt</spanx> or <spanx style="verb">sop sign</spanx> implementation that stages multiple decryption attempts like this <bcp14>SHOULD</bcp14> consider the computational resources consumed by each attempt, to avoid presenting an attack surface for resource exhaustion in the face of a non-standard <spanx style="verb">PASSWORD</spanx> input.</t>

</section>
</section>
<section anchor="special-designators-guidance"><name>Be Careful with Special Designators</name>

<t>As documented in <xref target="special-designators"/>, special designators for indirect inputs like <spanx style="verb">@ENV:</spanx> and <spanx style="verb">@FD:</spanx> (and indirect outputs using <spanx style="verb">@FD:</spanx>) warrant some special/cautious handling.</t>

<t>For one thing, it's conceivable that the filesystem could contain a file with these literal names.
If <spanx style="verb">sop</spanx> receives an indirect output parameter that starts with an <u>@</u> it <bcp14>MUST NOT</bcp14> write to the filesystem for that parameter.
A <spanx style="verb">sop</spanx> implementation that receives such a parameter as input <bcp14>MAY</bcp14> test for the presence of such a file in the filesystem and fail with <spanx style="verb">AMBIGUOUS_INPUT</spanx> to warn the user of the ambiguity and possible confusion.</t>

<t>These special designators are likely to be used to pass sensitive data (like secret key material or passwords) so that it doesn't need to touch the filesystem.
Given this sensitivity, <spanx style="verb">sop</spanx> should be careful with such an input, and minimize its leakage to other processes.
In particular, <spanx style="verb">sop</spanx> <bcp14>SHOULD NOT</bcp14> leak any environment variable identified by <spanx style="verb">@ENV:</spanx> or file descriptor identified by <spanx style="verb">@FD:</spanx> to any subprocess unless the subprocess specifically needs access to that data.</t>

</section>
<section anchor="hardware-backed-secrets"><name>Nuances for Hardware-backed Secret Key Material</name>

<t>There are a number of limitations and nuances to be aware of for hardware-backed secret key support in this interface.
Some <spanx style="verb">sop</spanx> implementations will simply not support hardware-backed secret key material.
Other implementations might support only a single kind of hardware-backing (e.g., an OpenPGP Smartcard <xref target="OPENPGP-SMARTCARD"/> but not a TPM, or vice versa).</t>

<t>There is no formally adopted OpenPGP standard for identifying that a given secret key is backed by hardware based on the OpenPGP wire format.
<xref target="I-D.dkg-openpgp-external-secrets"/> proposes one simple and straightforward approach for how the wire format could cover this use case.
This simple mechanism is deliberately agnostic about the specific kind of cryptographic hardware, but it does imply a sort of rough shape of what the interface to the hardware would permit.
In particular, it will work best with hardware that has the following properties:</t>

<t><list style="symbols">
  <t>The hardware does specific asymmetric secret key operations, using secret keys that it does not release.</t>
  <t>The user can ask the hardware to provide a list of corresponding public key material (or OpenPGP key fingerprints) for any of the secret keys held by the device.</t>
  <t>The hardware <bcp14>MAY</bcp14> require the provision of a PIN or password to enable secret key operation, but does not require a PIN or password for the list of public key material.</t>
</list></t>

<t>The <spanx style="verb">sop</spanx> interface does not currently provide for provisioning cryptographic hardware with secret key material, or for changing the PIN or password for the cryptographic hardware.
Users of cryptographic hardware need to do provisioning and PIN or password setting outside of <spanx style="verb">sop</spanx>.</t>

<t>If a user has two attached hardware tokens that both hold the same secret key, and they are both password-locked, and they use different passwords, <spanx style="verb">sop</spanx> offers no way for the user to clearly indicate which password belongs to which device.
Some cryptographic hardware is designed to lock the device if the wrong password is entered too many times, so users in this configuration are at risk of accidental lockout.
The easiest resolution for this is for the user to detach any duplicate devices before invoking <spanx style="verb">sop</spanx>.</t>

<t>Note that some OpenPGP implementations use the private codepoint ranges in the OpenPGP specification within an OpenPGP Transferable Secret Key (e.g., <xref target="GNUPG-SECRET-STUB"/>) to indicate that the secret key can be found on a smartcard.</t>

<t>While hardware-backed secret key operations can be significantly slower than modern computers, and physical affordances like button-presses or NFC tapping can themselves incur delay, it's bad form for an invocation of <spanx style="verb">sop</spanx> to hang forever.
This specification doesn't define a specific maximum allowable delay, but if an implementation calls into a hardware device either for public key listing or for secret key operations, it should not allow the cryptographic hardware to take an arbitrary amount of time to respond.</t>

</section>
<section anchor="statelessness-exemptions"><name>Statelessness exemptions</name>

<t>While this specification strives to define all operations as stateless implementers <bcp14>MAY</bcp14>, for practical reasons, rely on the global state of the system.</t>

<t>For example, the following items constitute a system state but are not considered to violate the stateless rule:</t>

<t><list style="symbols">
  <t>current time</t>
</list></t>

<t>Implementers are advised to document which global state items they rely on to help in troubleshooting issues for consumers.</t>

</section>
</section>
<section anchor="guidance-for-consumers"><name>Guidance for Consumers</name>

<t>While <spanx style="verb">sop</spanx> is originally conceived of as an interface for interoperability testing, it's conceivable that an application that uses OpenPGP for object security would want to use it.</t>

<t>FIXME: more guidance for how to use such a tool safely and efficiently goes here.</t>

<t>FIXME: if an encrypted OpenPGP message arrives without metadata, it is difficult to know which signers to consider when decrypting.
How do we do this efficiently without invoking <spanx style="verb">sop decrypt</spanx> twice, once without <spanx style="verb">--verify-*</spanx> and again with the expected identity material?</t>

<section anchor="choosing-between-astext-and-asbinary"><name>Choosing Between --as=text and --as=binary</name>

<t>A program that invokes <spanx style="verb">sop</spanx> to generate an OpenPGP signature typically needs to decide whether it is making a text or binary signature.</t>

<t>By default, <spanx style="verb">sop</spanx> will make a binary signature.
The caller of <spanx style="verb">sop sign</spanx> should choose <spanx style="verb">--as=text</spanx> only when it knows that:</t>

<t><list style="symbols">
  <t>the data being signed is in fact textual, and encoded in <spanx style="verb">UTF-8</spanx>, and</t>
  <t>the signed data might be transmitted to the recipient (the verifier of the signature) over a channel that has the propensity to transform line-endings.</t>
</list></t>

<t>Examples of such channels include FTP (<xref target="RFC0959"/>) and SMTP (<xref target="RFC5321"/>).</t>

</section>
<section anchor="special-designators-and-unusual-filenames"><name>Special Designators and Unusual Filenames</name>

<t>In some cases, a user of <spanx style="verb">sop</spanx> might want to pass all the files in a given directory as positional parameters (e.g., a list of CERTS files to test a signature against).</t>

<t>If one of the files has a name that starts with <spanx style="verb">--</spanx>, it might be confused by <spanx style="verb">sop</spanx> for an option.
If one of the files has a name that starts with <spanx style="verb">@</spanx>, it might be confused by <spanx style="verb">sop</spanx> as a special designator (<xref target="special-designators"/>).</t>

<t>If the user wants to deliberately refer to such an ambiguously-named file in the filesystem, they should prefix the filename with  <spanx style="verb">./</spanx> or use an absolute path.</t>

<t>Any specific <spanx style="verb">@FD:</spanx> special designator <bcp14>SHOULD NOT</bcp14> be supplied more than once to an invocation of <spanx style="verb">sop</spanx>.
If a <spanx style="verb">sop</spanx> invocation sees multiple copies of a specific <spanx style="verb">@FD:n</spanx> input (e.g., <spanx style="verb">sop sign @FD:3 @FD:3</spanx>),
it <bcp14>MAY</bcp14> fail with <spanx style="verb">MISSING_INPUT</spanx> even if file descriptor 3 contains a valid <spanx style="verb">KEYS</spanx>, because the bytestream for the <spanx style="verb">KEYS</spanx> was consumed by the first argument.
Doubling up on the same <spanx style="verb">@FD:</spanx> for output (e.g., <spanx style="verb">sop decrypt --session-key-out=@FD:3 --verifications-out=@FD:3</spanx>) also results in an ambiguous data stream.</t>

</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>

<t>The OpenPGP object security model is typically used for confidentiality and authenticity purposes.</t>

<section anchor="signature-verification"><name>Signature Verification</name>

<t>In many contexts, an OpenPGP signature is verified to prove the origin and integrity of an underlying object.</t>

<t>When <spanx style="verb">sop</spanx> checks a signature over data (e.g., via <spanx style="verb">sop verify</spanx> or <spanx style="verb">sop decrypt --verify-with</spanx>), it <bcp14>MUST NOT</bcp14> consider it to be verified unless all of these conditions are met:</t>

<t><list style="symbols">
  <t>The signature must be made by a signing-capable public key that is present in one of the supplied certificates</t>
  <t>The certificate and signing component key must have been created before or at the signature time</t>
  <t>The certificate and signing component key must not have been expired at the signature time</t>
  <t>The certificate and signing component key must not be revoked with a "hard" revocation</t>
  <t>If the certificate or signing component key is revoked with a "soft" revocation, then the signature time must predate the revocation</t>
  <t>If the signing component key is a subkey, that subkey must be properly bound to the primary key, and cross-signed</t>
  <t>The signature (and any dependent signature, such as the cross-sig or subkey binding signatures) must be made with strong cryptographic algorithms (e.g., not <spanx style="verb">MD5</spanx> or a 1024-bit <spanx style="verb">RSA</spanx> key)</t>
  <t>The signature must be of type 0x00 ("Signature of a binary document") or 0x01 ("Signature of a canonical text document"); other signature types are inappropriate for data signatures</t>
</list></t>

<t>Implementers <bcp14>MAY</bcp14> also consider other factors in addition to the origin and authenticity, including application-specific information.</t>

<t>For example, consider the application domain of checking software updates.
If software package Foo version 13.3.2 was signed on 2019-10-04, and the user receives a copy of Foo version 12.4.8 that was signed on 2019-10-16, it may be authentic and have a more recent signature date.
But it is not an upgrade (12.4.8 &lt; 13.3.2), and therefore it should not be applied automatically.</t>

<t>In such cases, it is critical that the application confirms that the other information verified is <em>also</em> protected by the relevant OpenPGP signature.</t>

<t>Signature validity is a complex topic (see for example the discussion at <xref target="DISPLAYING-SIGNATURES"/>), and this documentation cannot list all possible details.</t>

<section anchor="explaining-non-verification"><name>Explaining Non-Verification on Standard Error</name>

<t>When verifying OpenPGP signatures, sometimes no valid signatures are found.
This will cause the verifying subcommand to produce an empty <spanx style="verb">VERIFICATIONS</spanx> output, and for some subcommands (<spanx style="verb">sop verify</spanx> and <spanx style="verb">sop inline-verify</spanx> in particular) will also cause the subcommand to fail with <spanx style="verb">NO_SIGNATURE</spanx>.</t>

<t>When this happens, some consumers will want to know more details about the verification failure, since some verification failures may be indications that something is wrong with the verifier's setup, such as outdated OpenPGP implementations (which can be upgraded), expired signing certificates (which can be refreshed), and so on.</t>

<t>To address this, when no valid signatures are found at all, <spanx style="verb">sop</spanx> <bcp14>MAY</bcp14> emit a human-readable explanation to standard error.</t>

<t>Some example explanations for complete signature validation failure include:</t>

<t><list style="symbols">
  <t>Version 7 signature found, but FooPGP 2.0.3 only supports versions 4 and 6.</t>
  <t>Version 3 signature found, but BarPGP 0.9.7 rejects all version 3 signatures.</t>
  <t>Signature from pubkey algorithm 94 found, but BazPGP 1.1 does not support this pubkey algorithm.</t>
  <t>Signature using hash algorithm 22 found, but QuxPGP 19.0.5 does not support this hash algorithm.</t>
  <t>Two signatures found, both made by unknown OpenPGP certificates.</t>
  <t>Signature does not match hash prefix.</t>
  <t>No OpenPGP signatures found.</t>
</list></t>

<t>In some cases (such as when two OpenPGP signatures are discovered, and they both fail to validate for different reasons), a <spanx style="verb">sop</spanx> implementation may choose to emit a more complex warning.</t>

<t>Unless <spanx style="verb">--debug</spanx> is present, <spanx style="verb">sop</spanx> <bcp14>SHOULD NOT</bcp14> emit any such warning (even if true for one of the OpenPGP signatures found) if another signature was found in the same <spanx style="verb">SIGNATURES</spanx> object or <spanx style="verb">INLINESIGNED</spanx> message that does verify correctly.
This keeps the upgrade path smooth for the whole ecosystem.
As the ecosystem evolves, signatures using new versions and algorithms, or signatures simply using new signing keys, are typically introduced as a second signature distributed alongside the first.
A warning about a signature with a new or unknown algorithm (or key) when an accompanying signature still verifies from a known key with a known algorithm will discourage signers from adopting new algorithms or keys.
And introducing a warning about a signature using a deprecated algorithm (or key), when an accompanying signature still verifies using a more modern algorithm or key will discourage a verifier from upgrading their OpenPGP implementation or dropping old, deprecated keys.</t>

<t>Implementers should avoid emitting dangerous explanations.
For example, an explanation like "Signature from 0xDEADBEEF found, but not in list of acceptable signers" might encourage a user to go hunting for any certificate with short key ID 0xDEADBEEF and start using it to verify signatures.
This would be a very dangerous explanation, in particular because short key IDs are trivially forgeable.
But it would also be nearly as dangerous to use a full fingerprint (instead of a short Key ID) in such a message because then all an attacker has to do is to get their signature to appear in the place where the verifier is looking for a signature, and then the warning will encourage the verifier go look up the attacker's certificate by fingerprint.</t>

<t>An internationalized, locale-aware <spanx style="verb">sop</spanx> implementation should localize these warning messages.</t>

</section>
</section>
<section anchor="compression"><name>Compression</name>

<t>The interface as currently specified does not allow for control of compression.
Compressing and encrypting data that may contain both attacker-supplied material and sensitive material could leak information about the sensitive material (see the CRIME attack).</t>

<t>Unless an application knows for sure that no attacker-supplied material is present in the input, it should not compress during encryption.</t>

</section>
</section>
<section anchor="privacy-considerations"><name>Privacy Considerations</name>

<t>Material produced by <spanx style="verb">sop encrypt</spanx> may be placed on an untrusted machine (e.g., sent through the public <spanx style="verb">SMTP</spanx> network).
That material may contain metadata that leaks associational information (e.g., recipient identifiers in PKESK packets (<xref section="5.1" sectionFormat="of" target="RFC9580"/>)).
FIXME: document things like PURBs and <spanx style="verb">--hidden-recipient</spanx>)</t>

<section anchor="object-security-vs-transport-security"><name>Object Security vs. Transport Security</name>

<t>OpenPGP offers an object security model, but says little to nothing about how the secured objects get to the relevant parties.</t>

<t>When sending or receiving OpenPGP material, the implementer should consider what privacy leakage is implicit with the transport.</t>

</section>
</section>


  </middle>

  <back>


<references title='References' anchor="sec-combined-references">

    <references title='Normative References' anchor="sec-normative-references">



<reference anchor="RFC2119">
  <front>
    <title>Key words for use in RFCs to Indicate Requirement Levels</title>
    <author fullname="S. Bradner" initials="S." surname="Bradner"/>
    <date month="March" year="1997"/>
    <abstract>
      <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="2119"/>
  <seriesInfo name="DOI" value="10.17487/RFC2119"/>
</reference>
<reference anchor="RFC8174">
  <front>
    <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
    <author fullname="B. Leiba" initials="B." surname="Leiba"/>
    <date month="May" year="2017"/>
    <abstract>
      <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="8174"/>
  <seriesInfo name="DOI" value="10.17487/RFC8174"/>
</reference>
<reference anchor="RFC9580">
  <front>
    <title>OpenPGP</title>
    <author fullname="P. Wouters" initials="P." role="editor" surname="Wouters"/>
    <author fullname="D. Huigens" initials="D." surname="Huigens"/>
    <author fullname="J. Winter" initials="J." surname="Winter"/>
    <author fullname="Y. Niibe" initials="Y." surname="Niibe"/>
    <date month="July" year="2024"/>
    <abstract>
      <t>This document specifies the message formats used in OpenPGP. OpenPGP provides encryption with public key or symmetric cryptographic algorithms, digital signatures, compression, and key management.</t>
      <t>This document is maintained in order to publish all necessary information needed to develop interoperable applications based on the OpenPGP format. It is not a step-by-step cookbook for writing an application. It describes only the format and methods needed to read, check, generate, and write conforming packets crossing any network. It does not deal with storage and implementation questions. It does, however, discuss implementation issues necessary to avoid security flaws.</t>
      <t>This document obsoletes RFCs 4880 ("OpenPGP Message Format"), 5581 ("The Camellia Cipher in OpenPGP"), and 6637 ("Elliptic Curve Cryptography (ECC) in OpenPGP").</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="9580"/>
  <seriesInfo name="DOI" value="10.17487/RFC9580"/>
</reference>

<reference anchor="I-D.ietf-openpgp-replacementkey">
   <front>
      <title>OpenPGP Key Replacement</title>
      <author fullname="Daphne Shaw" initials="D." surname="Shaw">
         <organization>Jabberwocky Tech</organization>
      </author>
      <author fullname="Andrew Gallagher" initials="A." surname="Gallagher">
         <organization>PGPKeys.EU</organization>
      </author>
      <date day="29" month="May" year="2026"/>
      <abstract>
	 <t>   This document specifies a method in OpenPGP to suggest a replacement
   for an expired, revoked, or deprecated primary key.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-ietf-openpgp-replacementkey-08"/>
   
</reference>
<reference anchor="RFC3156">
  <front>
    <title>MIME Security with OpenPGP</title>
    <author fullname="M. Elkins" initials="M." surname="Elkins"/>
    <author fullname="D. Del Torto" initials="D." surname="Del Torto"/>
    <author fullname="R. Levien" initials="R." surname="Levien"/>
    <author fullname="T. Roessler" initials="T." surname="Roessler"/>
    <date month="August" year="2001"/>
    <abstract>
      <t>This document describes how the OpenPGP Message Format can be used to provide privacy and authentication using the Multipurpose Internet Mail Extensions (MIME) security content types described in RFC 1847. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="3156"/>
  <seriesInfo name="DOI" value="10.17487/RFC3156"/>
</reference>
<reference anchor="RFC3629">
  <front>
    <title>UTF-8, a transformation format of ISO 10646</title>
    <author fullname="F. Yergeau" initials="F." surname="Yergeau"/>
    <date month="November" year="2003"/>
    <abstract>
      <t>ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world's writing systems. The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo. UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values. This memo obsoletes and replaces RFC 2279.</t>
    </abstract>
  </front>
  <seriesInfo name="STD" value="63"/>
  <seriesInfo name="RFC" value="3629"/>
  <seriesInfo name="DOI" value="10.17487/RFC3629"/>
</reference>



    </references>

    <references title='Informative References' anchor="sec-informative-references">

<reference anchor="OpenPGP-Interoperability-Test-Suite" target="https://tests.sequoia-pgp.org/">
  <front>
    <title>OpenPGP Interoperability Test Suite</title>
    <author >
      <organization></organization>
    </author>
    <date year="2021" month="October" day="25"/>
  </front>
</reference>
<reference anchor="Charset-Switching" target="https://dkg.fifthhorseman.net/notes/inline-pgp-harmful/">
  <front>
    <title>Inline PGP Considered Harmful</title>
    <author initials="D. K." surname="Gillmor" fullname="Daniel Kahn Gillmor">
      <organization></organization>
    </author>
    <date year="2014" month="February" day="24"/>
  </front>
</reference>
<reference anchor="Component-Keys" target="https://openpgp.dev/book/certificates.html#component-keys">
  <front>
    <title>OpenPGP for Application Developers: Certificates: Component Keys</title>
    <author initials="H." surname="Schaefer" fullname="Heiko Schaefer">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="DISPLAYING-SIGNATURES" target="https://admin.hostpoint.ch/pipermail/enigmail-users_enigmail.net/2017-November/004683.html">
  <front>
    <title>On Displaying Signatures</title>
    <author initials="P." surname="Brunschwig" fullname="Patrick Brunschwig">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="EFAIL" target="https://efail.de">
  <front>
    <title>Efail: Breaking S/MIME and OpenPGP Email Encryption using Exfiltration Channels</title>
    <author initials="D." surname="Poddebniak" fullname="Damian Poddebniak">
      <organization></organization>
    </author>
    <author initials="C." surname="Dresen" fullname="Christian Dresen">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="PYTHON-SOP" target="https://pypi.org/project/sop/">
  <front>
    <title>SOP for python</title>
    <author initials="D." surname="Gillmor" fullname="Daniel Kahn Gillmor">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="RUST-SOP" target="https://sequoia-pgp.gitlab.io/sop-rs/">
  <front>
    <title>A Rust implementation of the Stateless OpenPGP Protocol</title>
    <author initials="J." surname="Winter" fullname="Justus Winter">
      <organization>Sequoia</organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="SEMVER" target="https://semver.org/">
  <front>
    <title>Semantic Versioning 2.0.0</title>
    <author initials="T." surname="Preston-Werner" fullname="Tom Preston-Werner">
      <organization></organization>
    </author>
    <date year="2013" month="June" day="18"/>
  </front>
</reference>
<reference anchor="SOP-JAVA" target="https://github.com/pgpainless/sop-java">
  <front>
    <title>Stateless OpenPGP Protocol for Java.</title>
    <author initials="P." surname="Schaub" fullname="Paul Schaub">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="UNICODE-NORMALIZATION" target="https://unicode.org/reports/tr15/">
  <front>
    <title>Unicode Normalization Forms</title>
    <author initials="K." surname="Whistler" fullname="Ken Whistler">
      <organization>Unicode Consortium</organization>
    </author>
    <date year="2019" month="February" day="04"/>
  </front>
</reference>
<reference anchor="OPENPGP-SMARTCARD" target="https://www.gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf">
  <front>
    <title>Functional Specification of the OpenPGP application on ISO Smart Card Operating Systems, Version 3.4</title>
    <author initials="A." surname="Pietig" fullname="Achim Pietig">
      <organization></organization>
    </author>
    <date year="2020" month="March" day="18"/>
  </front>
</reference>
<reference anchor="GNUPG-SECRET-STUB" target="https://dev.gnupg.org/source/gnupg/browse/master/doc/DETAILS;gnupg-2.4.3$1511">
  <front>
    <title>GNU Extensions to the S2K algorithm</title>
    <author initials="W." surname="Koch" fullname="Werner Koch">
      <organization>g10 Code</organization>
    </author>
    <date year="2023" month="July" day="04"/>
  </front>
</reference>
<reference anchor="DKG-SOP" target="https://git.savannah.nongnu.org/cgit/dkgpg.git/tree/tools/dkg-sop.cc">
  <front>
    <title>dkg-sop</title>
    <author initials="H." surname="Stamer" fullname="Heiko Stamer">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="GOSOP" target="https://github.com/ProtonMail/gosop">
  <front>
    <title>gosop</title>
    <author >
      <organization>Proton</organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="GPGME-SOP" target="https://gitlab.com/sequoia-pgp/gpgme-sop">
  <front>
    <title>gpgme-sop</title>
    <author initials="J." surname="Winter" fullname="Justus Winter">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="MSOP" target="https://codeberg.org/minipgp6/minipgp6">
  <front>
    <title>msop</title>
    <author initials="H." surname="Schaefer" fullname="Heiko Schaefer">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="PGPAINLESS-CLI" target="https://codeberg.org/PGPainless/pgpainless/src/branch/master/pgpainless-sop">
  <front>
    <title>pgpainless-cli</title>
    <author initials="P." surname="Schaub" fullname="Paul Schaub">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="RNP-SOP" target="https://gitlab.com/sequoia-pgp/rnp-sop">
  <front>
    <title>rnp-sop</title>
    <author initials="J." surname="Winter" fullname="Justus Winter">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="RSOP" target="https://codeberg.org/heiko/rsop">
  <front>
    <title>rsop</title>
    <author initials="H." surname="Schaefer" fullname="Heiko Schaefer">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="SQOP" target="https://gitlab.com/sequoia-pgp/sequoia-sop">
  <front>
    <title>sqop</title>
    <author >
      <organization>Sequoia PGP</organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="SOP-OPENPGPJS" target="https://github.com/openpgpjs/sop-openpgpjs">
  <front>
    <title>sop-openpgp.js</title>
    <author >
      <organization>Proton</organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="SOPGPY" target="https://github.com/SecurityInnovation/PGPy/pull/440">
  <front>
    <title>sopgpy</title>
    <author initials="D. K." surname="Gillmor" fullname="Daniel Kahn Gillmor">
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>



<reference anchor="I-D.draft-bre-openpgp-samples-01">
   <front>
      <title>OpenPGP Example Keys and Certificates</title>
      <author fullname="Bjarni Rúnar Einarsson" initials="B. R." surname="Einarsson">
         <organization>Mailpile ehf</organization>
      </author>
      <author fullname="&quot;juga&quot;" initials="" surname="&quot;juga&quot;">
         <organization>Independent</organization>
      </author>
      <author fullname="Daniel Kahn Gillmor" initials="D. K." surname="Gillmor">
         <organization>American Civil Liberties Union</organization>
      </author>
      <date day="20" month="December" year="2019"/>
      <abstract>
	 <t>   The OpenPGP development community benefits from sharing samples of
   signed or encrypted data.  This document facilitates such
   collaboration by defining a small set of OpenPGP certificates and
   keys for use when generating such samples.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-bre-openpgp-samples-01"/>
   
</reference>
<reference anchor="RFC4880">
  <front>
    <title>OpenPGP Message Format</title>
    <author fullname="J. Callas" initials="J." surname="Callas"/>
    <author fullname="L. Donnerhacke" initials="L." surname="Donnerhacke"/>
    <author fullname="H. Finney" initials="H." surname="Finney"/>
    <author fullname="D. Shaw" initials="D." surname="Shaw"/>
    <author fullname="R. Thayer" initials="R." surname="Thayer"/>
    <date month="November" year="2007"/>
    <abstract>
      <t>This document is maintained in order to publish all necessary information needed to develop interoperable applications based on the OpenPGP format. It is not a step-by-step cookbook for writing an application. It describes only the format and methods needed to read, check, generate, and write conforming packets crossing any network. It does not deal with storage and implementation questions. It does, however, discuss implementation issues necessary to avoid security flaws.</t>
      <t>OpenPGP software uses a combination of strong public-key and symmetric cryptography to provide security services for electronic communications and data storage. These services include confidentiality, key management, authentication, and digital signatures. This document specifies the message formats used in OpenPGP. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="4880"/>
  <seriesInfo name="DOI" value="10.17487/RFC4880"/>
</reference>
<reference anchor="RFC2440">
  <front>
    <title>OpenPGP Message Format</title>
    <author fullname="J. Callas" initials="J." surname="Callas"/>
    <author fullname="L. Donnerhacke" initials="L." surname="Donnerhacke"/>
    <author fullname="H. Finney" initials="H." surname="Finney"/>
    <author fullname="R. Thayer" initials="R." surname="Thayer"/>
    <date month="November" year="1998"/>
    <abstract>
      <t>This document is maintained in order to publish all necessary information needed to develop interoperable applications based on the OpenPGP format. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="2440"/>
  <seriesInfo name="DOI" value="10.17487/RFC2440"/>
</reference>

<reference anchor="I-D.ietf-lamps-e2e-mail-guidance-11">
   <front>
      <title>Guidance on End-to-End E-mail Security</title>
      <author fullname="Daniel Kahn Gillmor" initials="D. K." surname="Gillmor">
         <organization>American Civil Liberties Union</organization>
      </author>
      <author fullname="Bernie Hoeneisen" initials="B." surname="Hoeneisen">
         <organization>pEp Foundation</organization>
      </author>
      <author fullname="Alexey Melnikov" initials="A." surname="Melnikov">
         <organization>Isode Ltd</organization>
      </author>
      <date day="8" month="August" year="2023"/>
      <abstract>
	 <t>   End-to-end cryptographic protections for e-mail messages can provide
   useful security.  However, the standards for providing cryptographic
   protection are extremely flexible.  That flexibility can trap users
   and cause surprising failures.  This document offers guidance for
   mail user agent implementers to help mitigate those risks, and to
   make end-to-end e-mail simple and secure for the end user.  It
   provides a useful set of vocabulary as well as suggestions to avoid
   common failures.  It also identifies a number of currently unsolved
   usability and interoperability problems.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-ietf-lamps-e2e-mail-guidance-11"/>
   
</reference>

<reference anchor="I-D.dkg-openpgp-external-secrets">
   <front>
      <title>OpenPGP External Secret Keys</title>
      <author fullname="Daniel Kahn Gillmor" initials="D. K." surname="Gillmor">
         <organization>American Civil Liberties Union</organization>
      </author>
      <date day="12" month="September" year="2025"/>
      <abstract>
	 <t>   This document defines a standard wire format for indicating that the
   secret component of an OpenPGP asymmetric key is stored externally,
   for example on a hardware device or other comparable subsystem.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-dkg-openpgp-external-secrets-02"/>
   
</reference>
<reference anchor="RFC0959">
  <front>
    <title>File Transfer Protocol</title>
    <author fullname="J. Postel" initials="J." surname="Postel"/>
    <author fullname="J. Reynolds" initials="J." surname="Reynolds"/>
    <date month="October" year="1985"/>
    <abstract>
      <t>This memo is the official specification of the File Transfer Protocol (FTP) for the DARPA Internet community. The primary intent is to clarify and correct the documentation of the FTP specification, not to change the protocol. The following new optional commands are included in this edition of the specification: Change to Parent Directory (CDUP), Structure Mount (SMNT), Store Unique (STOU), Remove Directory (RMD), Make Directory (MKD), Print Directory (PWD), and System (SYST). Note that this specification is compatible with the previous edition.</t>
    </abstract>
  </front>
  <seriesInfo name="STD" value="9"/>
  <seriesInfo name="RFC" value="959"/>
  <seriesInfo name="DOI" value="10.17487/RFC0959"/>
</reference>
<reference anchor="RFC5321">
  <front>
    <title>Simple Mail Transfer Protocol</title>
    <author fullname="J. Klensin" initials="J." surname="Klensin"/>
    <date month="October" year="2008"/>
    <abstract>
      <t>This document is a specification of the basic protocol for Internet electronic mail transport. It consolidates, updates, and clarifies several previous documents, making all or parts of most of them obsolete. It covers the SMTP extension mechanisms and best practices for the contemporary Internet, but does not provide details about particular extensions. Although SMTP was designed as a mail transport and delivery protocol, this specification also contains information that is important to its use as a "mail submission" protocol for "split-UA" (User Agent) mail reading systems and mobile environments. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="5321"/>
  <seriesInfo name="DOI" value="10.17487/RFC5321"/>
</reference>



    </references>

</references>


<?line 1835?>

<section anchor="sopv-changelog"><name>sopv Version Changelog</name>

<t>This is a reverse-chronological order changelog for the <spanx style="verb">sopv</spanx> subset.
This versioning scheme aims for compliance with <xref target="SEMVER"/>.</t>

<section anchor="sopv-1.2"><name>sopv Version 1.2</name>

<t><spanx style="verb">sopv</spanx> 1.2 adds the certificate verification, via the following subcommand:</t>

<t><list style="symbols">
  <t><spanx style="verb">sop validate-userid</spanx></t>
</list></t>

</section>
<section anchor="sopv-1.1"><name>sopv Version 1.1</name>

<t><list style="symbols">
  <t><spanx style="verb">VERIFICATIONS</spanx> output always includes the fourth <spanx style="verb">mode:</spanx> field</t>
  <t><spanx style="verb">VERIFICATIONS</spanx> output always uses JSON format for the trailer of each line, and always populates the <spanx style="verb">signers</spanx> member (see <xref target="verifications-json"/>)</t>
</list></t>

</section>
<section anchor="sopv-1.0"><name>sopv Version 1.0</name>

<t>The following subcommands:</t>

<t><list style="symbols">
  <t><spanx style="verb">sop version</spanx></t>
  <t><spanx style="verb">sop verify</spanx></t>
  <t><spanx style="verb">sop inline-verify</spanx></t>
</list></t>

<t>And the following features:</t>

<t><list style="symbols">
  <t>Special designators <spanx style="verb">@FD:</spanx> and <spanx style="verb">@ENV:</spanx> as input for any <spanx style="verb">CERTS</spanx> object or <spanx style="verb">SIGNATURES</spanx> object</t>
  <t>Special designator <spanx style="verb">@FD:</spanx> as possible output for the <spanx style="verb">VERIFICATIONS</spanx> object in <spanx style="verb">sopv inline-verify --verifications-out</spanx></t>
  <t>Multiple certificates in each <spanx style="verb">CERTS</spanx> object</t>
  <t><spanx style="verb">--not-before</spanx> and <spanx style="verb">--not-after</spanx> constraints</t>
</list></t>

</section>
</section>
<section anchor="libsop"><name>C Library API (Tentative)</name>

<t>As specified in this draft, SOP is a command-line tool.</t>

<t>However, it can also be useful to have a comparable API exposed as a C library.
This library can be implemented as a shared object (e.g., <spanx style="verb">.so</spanx>, <spanx style="verb">.dll</spanx>, or <spanx style="verb">.dylib</spanx> depending on the platform) or as a statically linked object.
This interface can be reused in many different places, as most modern programming languages offer "bindings" to C libraries.</t>

<t>A proposed interface to a C library follows here as a C header file.</t>

<t>The primary goal of this shared object interface is to make it easy to implement the command-line interface described in this document.
That said, it is also intended to be relatively ergonomic to use in plausible OpenPGP workflows where the caller has access to all of the explicit state.</t>

<t>If there is a plausible OpenPGP workflow that is not supported by this library API, please propose improvements and explain the specific workflow.</t>

<t>The verification-only subset is defined in <spanx style="verb">sopv.h</spanx>:</t>

<figure><sourcecode type="text/x-chdr" name="sopv.h"><![CDATA[
/* -*- mode: c; fill-column: 60; -*- */
#ifndef __SOPV_H__
#define __SOPV_H__

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>

/* C API for Stateless OpenPGP Verification-only Subset */

/* Depends on C99 */


/* statically-defined, non-opaque definitions */

typedef enum {
  SOP_OK = 0,
  SOP_INTERNAL_ERROR = 1, /* Not part of sop CLI */
  SOP_INVALID_ARG = 2, /* Not part of sop CLI */
  SOP_NO_SIGNATURE = 3,
  SOP_OPERATION_ALREADY_EXECUTED = 4, /* Not part of sop CLI */
  SOP_UNSUPPORTED_ASYMMETRIC_ALGO = 13,
  SOP_CERT_CANNOT_ENCRYPT = 17,
  SOP_MISSING_ARG = 19,
  SOP_INCOMPLETE_VERIFICATION = 23,
  SOP_CANNOT_DECRYPT = 29,
  SOP_PASSWORD_NOT_HUMAN_READABLE = 31,
  SOP_UNSUPPORTED_OPTION = 37,
  SOP_BAD_DATA = 41,
  SOP_EXPECTED_TEXT = 53,
  SOP_OUTPUT_EXISTS = 59,
  SOP_MISSING_INPUT = 61,
  SOP_KEY_IS_PROTECTED = 67,
  SOP_UNSUPPORTED_SUBCOMMAND = 69,
  SOP_UNSUPPORTED_SPECIAL_PREFIX = 71,
  SOP_AMBIGUOUS_INPUT = 73,
  SOP_KEY_CANNOT_SIGN = 79,
  SOP_INCOMPATIBLE_OPTIONS = 83,
  SOP_UNSUPPORTED_PROFILE = 89,
  SOP_NO_HARDWARE_KEY_FOUND = 97,
  SOP_HARDWARE_KEY_FAILURE = 101,
  SOP_PRIMARY_KEY_BAD = 103,
  SOP_CERT_USERID_NO_MATCH = 107,
  SOP_KEY_CANNOT_CERTIFY = 109,

  /* ensures a stable size for the enum -- do not use! */
  SOP_MAX_ERR = INT_MAX,
} sop_err;
  

typedef enum {
  SOP_SIGN_AS_BINARY = 0,
  SOP_SIGN_AS_TEXT = 1,

  /* ensures a stable size for the enum -- do not use! */
  SOP_SIGN_AS_MAX = INT_MAX,
} sop_sign_as;


/* timestamps */
/* sop_time represents the number of seconds since the UNIX
 * epoch (1970-01-01T00:00:00Z) in a 64-bit signed integer.
 *
 * OpenPGP wire format timestamps (through RFC 9580 at
 * least) are internally unsigned 32-bit integers, which all
 * fall well within the range of sop_time.
 *
 * Despite sharing similar semantics to the traditional
 * time_t, sop_time doesn't use it explicitly, because on
 * some architectures time_t is a signed 32-bit integer,
 * which will roll over in 2038 and cannot express the range
 * of valid OpenPGP wire format timestamps.
 *
 * We also want sop_time to be able to explicitly represent
 * a "none" value as well as a "now" value without those
 * choices aliasing some legitimate value in the explicitly
 * supported wire format range. */
typedef int64_t sop_time;
#define sop_time_none ((sop_time)(INT64_MIN))
#define sop_time_now ((sop_time)(INT64_MIN+1))


/* Context object
 *
 * Each SOP object is bound back to a context object, and,
 * when used in combination with other SOP objects, all SOP
 * objects should come from the same context.
 *
 * A SOP context object need not be thread-safe; it should
 * probably not be used across multiple threads.  See "Zero
 * global state" in the README file in
 * https://git.kernel.org/pub/scm/linux/kernel/git/kay/libabc.git
 *
 * sopv: 1.0
 */

struct sop_ctx_st;
typedef struct sop_ctx_st sop_ctx;

sop_ctx*
sop_ctx_new ();
void
sop_ctx_free (sop_ctx *sop);

/* Logging: */

typedef enum {
  SOP_LOG_NEVER = 0,
  SOP_LOG_ERROR = 1,
  SOP_LOG_WARNING = 2,
  SOP_LOG_INFO = 3,
  SOP_LOG_DEBUG = 4,

  /* ensures a stable size for the enum -- do not use! */
  SOP_LOG_MAX = INT_MAX,
} sop_log_level;

static inline const char *
sop_log_level_name (sop_log_level log_level) {
#define rep(x) if (log_level == SOP_LOG_ ## x) return #x
  rep(ERROR);
  rep(WARNING);
  rep(INFO);
  rep(DEBUG);
#undef rep
  return "Unknown";
}

/* Handle warnings and other feedback.
 * 
 * A SOP implementation that is capable of producing log
 * messages will invoke the requested function with the log
 * level of the message, and a NULL-terminated UTF-8
 * human-readable string with no trailing whitespace.
 *
 * the "passthrough" pointer is supplied by the library user
 * via sop_set_log_level.
 *
 * sopv: 1.0
 */
typedef void (*sop_log_func) (sop_log_level log_level,
                              void *passthrough, const char *);
sop_err
sop_set_log_function (sop_ctx *sop, sop_log_func func,
                      void *passthrough);
/* Set the logging verbosity.
 *
 * Only log warnings up to max_level. (by default, max_level
 * is SOP_LOG_WARNING, meaning SOP_LOG_INFO and
 * SOP_LOG_DEBUG will be suppressed).
 *
 * sopv: 1.0
 */
sop_err
sop_set_log_level (sop_ctx *sop, sop_log_level max_level);



/* Information about the library: */

/* The name and version of the implementation of the C API
 * (simple NUL-terminated string, no newlines), or NULL if
 * there is an error producing the version.
 *
 * sopv: 1.0
 */
const char *
sop_version (sop_ctx *sop);
/* The name and version of the primary underlying OpenPGP
 * toolkit (or NULL if there is no backend, or if there was
 * an error producing the backend version)
 *
 * sopv: 1.0
 */
const char *
sop_version_backend (sop_ctx *sop);
/* Any arbitrary extended version information other than
 * sop_ctx_version.  Version info should be UTF-8 text,
 * separated by newlines (a NUL-terminated string, no
 * trailing newline).  Can return NULL if there is nothing
 * more to report beyond sop_version.
 *
 * sopv: 1.0
 */
const char *
sop_version_extended (sop_ctx *sop);

/* note: there is nothing comparable to sop version
 * --sop-spec because that should be visible based on the
 * exported symbols in the shared object */


/* CLEARTEXT (and other raw data): */

/* This is a standard buffer for bytestrings produced by
 *  sop.  Users never create this kind of object, but it is
 *  sometimes returned from the library.
 *
 * sopv: 1.0
 */
struct sop_buf_st;
typedef struct sop_buf_st sop_buf;

void
sop_buf_free (sop_buf *buf);
size_t
sop_buf_size (const sop_buf *buf);
const uint8_t *
sop_buf_data (const sop_buf *buf);


/* CERTS objects: This object represents a collection of
 * OpenPGP Certificates (Transferable Public Keys).  It can
 * also hold a copy of a caller-supplied label, which is a
 * NULL-terminated C string.
 *
 * sopv: 1.0
 */
struct sop_certs_st;
typedef struct sop_certs_st sop_certs;

/* data and len indicate the contiguous block of bytes that
 * will be parsed to create the CERTS object.
 *
 * label is a NULL-terminated C string.  It may be NULL.  If
 * label is not NULL, the implementation makes an internal
 * copy of the C string during sop_certs_from_bytes.
 */
sop_err
sop_certs_from_bytes (sop_ctx *sop,
                      const uint8_t *data, size_t len,
                      const char *label,
                      sop_certs **out);
void
sop_certs_free (sop_certs *certs);


/* Retreive a const pointer to the internal copy of the
 * CERTS object's label, or NULL if there is no label for
 * this CERTS object.
 *
 * sopv: 1.1
 */
sop_err
sop_certs_get_label (const sop_certs *certs,
                     const char **out);

/* SIGNATURES objects: This object represents a collection
 * of OpenPGP Signature packets
 *
 * sopv: 1.0
 */
struct sop_sigs_st;
typedef struct sop_sigs_st sop_sigs;

sop_err
sop_sigs_from_bytes (sop_ctx *sop,
                     const uint8_t *data, size_t len,
                     sop_sigs **out);
void
sop_sigs_free (sop_sigs *sigs);



/* VERIFICATIONS (output only, describes valid, verified
 * signatures):
 *
 * sopv: 1.0
 */
struct sop_verifications_st;
typedef struct sop_verifications_st sop_verifications;

void
sop_verifications_free (sop_verifications *verifs);
sop_err
sop_verifications_count (const sop_verifications *verifs,
                         size_t *out);
/* textual representations of verifications, in the form
 * described by VERIFICATIONS in the CLI
 *
 * sopv: 1.0
 */
sop_err
sop_verifications_to_text (const sop_verifications *verifs,
                           sop_buf **out);
/* returns SOP_INTERNAL_ERROR if index is out of bounds. */
sop_err
sop_verifications_get_time (const sop_verifications *verifs,
                            size_t index, sop_time *out);
/* returns SOP_INTERNAL_ERROR if index is out of bounds.  If
 * the signature is neither type 0x00 nor 0x01, this should
 * probably not be considered a valid, verified signature.
 *
 * sopv: 1.1
 */
sop_err
sop_verifications_get_mode (const sop_verifications *verifs,
                            size_t index, sop_sign_as *out);

/* returns SOP_INTERNAL_ERROR if index is out of bounds.
 *
 * sopv: 1.1
 */
sop_err
sop_verifications_get_signer_count (const sop_verifications *verifs,
                                    size_t index, size_t *out);

/* returns SOP_INTERNAL_ERROR if either verif_index or
 * signer_index is out of bounds.  Yields a pointer to the
 * sop_certs object that could have made the signature.
 *
 * sopv: 1.1
 */
sop_err
sop_verifications_get_signer (const sop_verifications *verifs,
                              size_t verif_index,
                              size_t signer_index,
                              const sop_certs **out);

/* FIXME: (do we want to get more detailed info
   programmatically?  each verification should also have an
   issuing key fingerprint, a primary key fingerprint, and a
   trailing text string) */

/* verify detached signatures:
 *
 *
 * sopv: 1.0
 */
struct sop_op_verify_st;
typedef struct sop_op_verify_st sop_op_verify;

sop_err
sop_op_verify_new (sop_ctx *sop, sop_op_verify **out);
void
sop_op_verify_free (sop_op_verify *verify);

sop_err
sop_op_verify_not_before (sop_op_verify *verify, sop_time when);
sop_err
sop_op_verify_not_after (sop_op_verify *verify, sop_time when);
sop_err
sop_op_verify_add_signers (sop_op_verify *verify,
                           const sop_certs *signers);

/* if no verifications are possible with the set of signers,
 * this returns SOP_NO_SIGNATURE, and *out is set to NULL
 *
 * sopv: 1.0
 */
sop_err
sop_op_verify_detached_execute (sop_op_verify *verify,
                                const sop_sigs *sigs,
                                const uint8_t *msg,
                                size_t sz,
                                sop_verifications **out);



/* INLINESIGNED object:
 *
 *
 * sopv: 1.0
 */
struct sop_inlinesigned_st;
typedef struct sop_inlinesigned_st sop_inlinesigned;

sop_err
sop_inlinesigned_from_bytes (sop_ctx *sop,
                             const uint8_t *data, size_t len,
                             sop_inlinesigned **out);
/* if the inlinesigned object uses the Cleartext Signing
 * framework, the armor parameter is ignored.
 *
 * sopv: 1.0
 */
void
sop_inlinesigned_free (sop_inlinesigned *inlinesigned);


/* sop inline-verify
 *
 *
 * sopv: 1.0
 */
sop_err
sop_op_verify_inline_execute (sop_op_verify *verify,
                              const sop_inlinesigned *msg,
                              sop_verifications **verifications_out,
                              sop_buf **msg_out);

/* sop validate-userid
 *
 * sopv: 1.2
 */
struct sop_op_validate_userid_st;
typedef struct sop_op_validate_userid_st sop_op_validate_userid;

sop_err
sop_op_validate_userid_new (sop_ctx *sop,
                            sop_op_validate_userid **out);

void
sop_op_validate_userid_free (sop_op_validate_userid *validate);

sop_err
sop_op_validate_userid_add_authority (sop_op_validate_userid *validate,
                                      const sop_certs *authority);

sop_err
sop_op_validate_userid_at (sop_op_validate_userid *validate,
                           sop_time when);

sop_err
sop_op_validate_userid_addr_spec_only (sop_op_validate_userid *validate,
                                       bool addr_spec_only);

sop_err
sop_op_validate_userid_execute (sop_op_validate_userid *validate,
                                const char *userid,
                                bool *out)

#endif /* __SOPV_H__ */
]]></sourcecode></figure>

<t>The rest of the stateless OpenPGP functionality is in <spanx style="verb">sop.h</spanx>, which explicitly includes <spanx style="verb">sopv.h</spanx>:</t>

<figure><sourcecode type="text/x-chdr" name="sop.h"><![CDATA[
/* -*- mode: c; fill-column: 60; -*- */

#ifndef __SOP_H__
#define __SOP_H__

#include <sopv.h>

/* C API for Stateless OpenPGP */
/* Depends on C99 */

typedef enum {
  SOP_INLINE_SIGN_AS_BINARY = 0,
  SOP_INLINE_SIGN_AS_TEXT = 1,
  SOP_INLINE_SIGN_AS_CLEARSIGNED = 2,

  /* ensures a stable size for the enum -- do not use! */
  SOP_INLINE_SIGN_AS_MAX = INT_MAX,
} sop_inline_sign_as;

typedef enum {
  SOP_ENCRYPT_AS_BINARY = 0,
  SOP_ENCRYPT_AS_TEXT = 1,

  /* ensures a stable size for the enum -- do not use! */
  SOP_ENCRYPT_AS_MAX = INT_MAX,
} sop_encrypt_as;

/* Serialize objects that sopv can read: */
sop_err
sop_certs_to_bytes (const sop_certs *certs,
                    bool armor, sop_buf **out);
sop_err
sop_sigs_to_bytes (const sop_sigs *sigs,
                   bool armor, sop_buf **out);
sop_err
sop_inlinesigned_to_bytes (const sop_inlinesigned *inlinesigned,
                           bool armor, sop_buf **out);

/* PROFILE objects: */

/* These describe a profile (e.g. for generate-key or
 * encrypt).  This use used when the implementation might
 * legitimately want to offer the user some minimal amount
 * of control over what is done.  The profile-listing
 * functions return blocks of four profiles.  A sop_profile
 * value of NULL represents no profile at all.  In a list of
 * sop_profile objects, once a NULL profile appears, no
 * non-NULL profiles may follow.
 
 */
struct sop_profile_st;
typedef struct sop_profile_st sop_profile;
/* the NUL-terminated string returned by sop_profile_name
   MUST be a UTF-8 encoded string, and MUST NOT include any
   whitespace or colon (`:`) characters.  It MUST NOT vary
   depending on locale. */
const char *
sop_profile_name (const sop_profile *profile);
/* The NUL-terminated string returned by
   sop_profile_description cannot contain any newlines, and
   it MAY vary depending on locale(7) if the implementation
   is internationalized. */
const char *
sop_profile_description (const sop_profile *profile);


#define SOP_MAX_PROFILE_COUNT 4

typedef struct {
  sop_profile *profile[SOP_MAX_PROFILE_COUNT];
} sop_profiles;

static inline size_t
sop_profiles_count(const sop_profiles profiles) {
  for (size_t i = 0; i < SOP_MAX_PROFILE_COUNT; i++)
    if (profiles.profile[i] == NULL)
      return i;
  return SOP_MAX_PROFILE_COUNT;
}

/* Return a list of profiles supported by the library for
 * generating keys.
 */
sop_err
sop_list_profiles_generate_key (sop_ctx *sop, sop_profiles *out);



/* KEYS objects: */
struct sop_keys_st;
typedef struct sop_keys_st sop_keys;

sop_err
sop_keys_from_bytes (sop_ctx *sop,
                     const uint8_t *data, size_t len,
                     sop_keys **out);
sop_err
sop_keys_to_bytes (const sop_keys *keys,
                   bool armor, sop_buf **out);
void
sop_keys_free (sop_keys *keys);



/* Generate a new, minimal OpenPGP Transferable secret key.
   `profile` can be NULL to mean the default profile. */
sop_err
sop_generate_key_with_profile (sop_ctx *sop,
                               sop_profile *profile,
                               bool sign_only,
                               sop_keys **out);

static inline sop_err
sop_generate_key (sop_ctx *sop, sop_keys **out) {
  return sop_generate_key_with_profile (sop, NULL, false, out);
}

/* For each key in the sop_keys object, add the given user
   ID, and return a new sop_keys object containing the
   updated keys.  If the supplied user ID is not valid UTF-8
   text, this call will fail and return SOP_EXPECTED_TEXT.

   If the implementation rejects the user ID string by
   policy for any other reason, this call will fail and
   return SOP_BAD_DATA.
 */
sop_err
sop_keys_add_uid (const sop_keys *keys, const char *uid,
                  sop_keys **out);

/* returns true if any of the secret key material is
   currently locked with a password */
sop_err
sop_keys_locked (const sop_keys *keys, bool *out);

/* return a new sop_keys object with any secret key material
   encrypted with `password` unlocked, Returns SOP_OK if all
   keys have now been unlocked.

   If any locked key material could not be unlocked, return
   SOP_KEY_IS_PROTECTED, while also unlocking what key
   material can be unlocked.

   This allows the user to try an arbitrary bytestream as a
   password.  Most users will just invoke the inlined
   sop_keys_unlock, below.

   An implementation MUST NOT reject proposed passwords by
   policy during unlock, but rather should try them as
   requested.
*/
sop_err
sop_keys_unlock_raw (const sop_keys *keys,
                     const uint8_t *raw_password, size_t len,
                     sop_keys **out);


static inline sop_err
sop_keys_unlock (const sop_keys *keys, const char *password,
                 sop_keys **out) {
  return sop_keys_unlock_raw (keys,
                              (const uint8_t *)password,
                              strlen (password),
                              out);
}


/* return a new sop_keys object where all secret key
   material is locked with `password` where possible.

   During locking, a safety-oriented implementation MAY
   reject the supplied password by policy for any number of
   reasons.  This helps libsop ensure that the proposed
   password can be successfully re-supplied during some
   future unlock attempt.

   If the implementation requires passwords to be UTF-8 text
   and the supplied password is not valid UTF-8, the
   implementation will fail, returning SOP_EXPECTED_TEXT.
   If an implementation rejects a supplied password for some
   other reason (for example, if it contains an NUL,
   unprintable, or otherwise forbidden character), this call
   will fail and return SOP_BAD_DATA.

   If any key material is already locked, it does nothing
   and returns SOP_KEY_IS_PROTECTED.

   Upon a successful locking, the user probably wants to use
   sop_keys_free to free the original keys object.
*/
sop_err
sop_keys_lock_raw (const sop_keys *keys,
                   const uint8_t *password, size_t len,
                   sop_keys **out);

static inline sop_err
sop_keys_lock (const sop_keys *keys, const char *password,
               sop_keys **out) {
  return sop_keys_lock_raw (keys,
                            (const uint8_t *)password,
                            strlen (password),
                            out);
}




/* Return the OpenPGP certificates ("Transferable Public
   Keys") that correspond to the OpenPGP Transferable Secret
   Keys. */
sop_err
sop_keys_extract_certs (const sop_keys *keys, sop_certs **out);


/* Return an OpenPGP revocation certificate for each
   Transferable Secret Key found in the input. */
sop_err
sop_keys_revoke_keys (const sop_keys *keys, sop_certs **out);



/* create detached signatures: */
struct sop_op_sign_st;
typedef struct sop_op_sign_st sop_op_sign;

sop_err
sop_op_sign_new (sop_ctx *sop, sop_op_sign **out);
void
sop_op_sign_free (sop_op_sign *sign);

sop_err
sop_op_sign_use_keys (sop_op_sign *sign, const sop_keys *keys);

sop_err
sop_op_sign_detached_execute (sop_op_sign *sign,
                              sop_sign_as sign_as,
                              const uint8_t *msg,
                              size_t sz,
                              sop_buf **micalg_out,
                              sop_sigs **out);

/* sop inline-sign */
sop_err
sop_op_sign_inline_execute (sop_op_sign *sign,
                            sop_inline_sign_as sign_as,
                            const uint8_t *msg,
                            size_t sz,
                            sop_inlinesigned **out);

/* sop inline-detach */
sop_err
sop_inlinesigned_detach (const sop_inlinesigned *msg,
                         sop_sigs **sigs_out,
                         sop_buf **msg_out);

#endif /* __SOP_H__ */
]]></sourcecode></figure>

<t>This proposed interface currently deals only with signing.
Encryption and decryption will be added in a future revision.</t>

<section anchor="design-choices-for-library-api"><name>Design Choices for Library API</name>

<t>The library is deliberately minimal, with data types and functionality corresponding to the SOP CLI.
The interface itself should expose no dependencies beyond libc.</t>

<t>All datatypes are opaque structs.
Library implementations <bcp14>MUST NOT</bcp14> expose library users to the memory layout of the underlying objects.</t>

<t>The library deals with data that is all in RAM, and produces data in RAM.
For simplicity, it does not currently expose a streaming interface.</t>

<t>It should be fairly straightforward to implement the SOP CLI on top of such a library.</t>

</section>
<section anchor="library-use-patterns"><name>Library Use Patterns</name>

<t>There are two main kinds of data structures: operations (e.g., <spanx style="verb">sop_op_sign</spanx> and <spanx style="verb">sop_op_verify</spanx>) and datatypes (e.g., <spanx style="verb">sop_keys</spanx> and <spanx style="verb">sop_certs</spanx>).</t>

<t>Operation objects are one-shot objects.
They are used in the following pattern:</t>

<t><list style="symbols">
  <t>create an operations object (<spanx style="verb">sop_op_*_new</spanx>)</t>
  <t>adjust it to behave in certain ways (e.g., <spanx style="verb">sop_op_sign_use_keys</spanx>, <spanx style="verb">sop_op_verify_not_before</spanx>)</t>
  <t>execute it (with some specific <spanx style="verb">sop_op_*_execute</spanx> function)</t>
  <t>dispose of it (<spanx style="verb">sop_op_*_free</spanx>)</t>
</list></t>

<t>The library user <bcp14>MUST NOT</bcp14> execute the same operation object more than once.
When a single operation object is executed more than once, it should fail with <spanx style="verb">SOP_OPERATION_ALREADY_EXECUTED</spanx>.
FIXME: if a use case arises with a reasonable need to re-execute an already adjusted object, we could extend the API to allow the user to clone an object.</t>

<t>Datatype objects are reusable objects.
For example, it is fine for a library user to pass the same <spanx style="verb">sop_certs</spanx> to multiple <spanx style="verb">sop_op_*</spanx> operation objects, as long as the <spanx style="verb">sop_certs</spanx> object is not freed before the execution of all the operation objects it has been passed to.</t>

<t>Datatype objects are also immutable.
Any function which modifies a datatype object always creates a new copy of the object, with the specific change applied.
This immutability avoids any ambiguity about what should happen when a datatype object is adjusted after it was passed to an operation object but before it was executed.</t>

</section>
<section anchor="libsopv-c-api-subset"><name><spanx style="verb">libsopv</spanx> C API Subset</name>

<t>A minimalist library subset that only does OpenPGP signature verification might be called <spanx style="verb">libsopv</spanx>.
This library is useful wherever the use case is just OpenPGP signature verification.</t>

<t>This minimal library interface should be sufficient to implement the <spanx style="verb">sopv</spanx> subset (see <xref target="sopv"/>).</t>

<section anchor="libsopv-11-c-api-subset"><name><spanx style="verb">libsopv</spanx> 1.1 C API Subset</name>

<t>Most functions in <spanx style="verb">sopv.h</spanx> are marked <spanx style="verb">sopv: 1.0</spanx>, indicating that they're necessary to support version 1.0 of the <spanx style="verb">sopv</spanx> subset.</t>

<t>The following four functions are additionally necessary to implement <spanx style="verb">sopv</spanx> version 1.1:</t>

<t><list style="symbols">
  <t><spanx style="verb">sop_verifications_get_mode</spanx></t>
  <t><spanx style="verb">sop_verifications_get_signer_count</spanx></t>
  <t><spanx style="verb">sop_verifications_get_signer</spanx></t>
  <t><spanx style="verb">sop_certs_get_label</spanx></t>
</list></t>

</section>
<section anchor="libsopv-12-c-api-subset"><name><spanx style="verb">libsopv</spanx> 1.2 C API Subset</name>

<t>And the following functions are additionally necessary to implement <spanx style="verb">sopv</spanx> version 1.2:</t>

<t><list style="symbols">
  <t><spanx style="verb">sop_op_validate_userid_new</spanx></t>
  <t><spanx style="verb">sop_op_validate_userid_free</spanx></t>
  <t><spanx style="verb">sop_op_validate_userid_add_authority</spanx></t>
  <t><spanx style="verb">sop_op_validate_userid_at</spanx></t>
  <t><spanx style="verb">sop_op_validate_userid_addr_spec_only</spanx></t>
  <t><spanx style="verb">sop_op_validate_userid_execute</spanx></t>
</list></t>

</section>
</section>
</section>
<section anchor="simple-self-test"><name>Simple CLI Test</name>

<t>The following POSIX-compliant shell script can be pointed to a SOP implementation.
It will report which subcommands have basic coverage.</t>

<t>It does not consider all possible combinations of all options.</t>

<figure><sourcecode type="text/x-sh" name="simple-sop-test"><![CDATA[
#!/bin/sh

# Simple, positive self-test for Stateless OpenPGP implementations

# https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/

# This does not test all possible combinations of options or
# argument structures, it merely confirms that the standard
# subcommands and options are all implemented.

# This code makes many simplifying assumptions (e.g., there is no
# whitespace or metacharacters in filenames; filenames follow a
# strict convention) in order to be simple POSIX-compliant shell.
# The invocations are not necessarily safe shell programming if
# those assumptions are not met.  Please use caution when borrowing
# from this test script.

# Author: Daniel Kahn Gillmor
# License: CC-0

SOP=$1

if [ -z "$SOP" ]; then
    cat >&2 <<EOF
Usage: $0 SOP

SOP should refer (either by \$PATH or by absolute path) to an
implementation of the Stateless OpenPGP command-line interface.
See https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/
EOF
    exit 1
fi

if ! COMMAND_OUTPUT=$(command -v "$SOP"); then
    printf >&2 "No such command: %s\n" "$SOP"
    exit 1
fi

shift

# We skip commands whose inputs are not available.
# Return 0 if the test should be skipped, 1 otherwise.
# missing inputs are printed to stdout.
skip_test() {
    # do not skip commands that consume no input.
    if [ "$1" = generate-key \
              -o "$1" = list-profiles \
              -o  "$1" = version ]; then
        return 1
    fi
    shift
    local arg=""
    local ret=1
    for arg in $SIN "$@"; do
        local noninput='^--\(\(.*out\|as\|profile\|userid\|'
        noninput="${noninput}"'validate-at\|\(verify-\|\)'
        noninput="${noninput}"'not-\(before\|after\)\)=\|[^=]*$\)'
        if printf %s "$arg" | grep -q "$noninput" ; then
            continue
        fi
        arg=$(printf %s "$arg" | sed 's/^--.*=\(.*\)$/\1/')
        if ! [ -r "$arg" ]; then
            ret=0
            printf ' %s' "$arg"
        fi
    done
    return "$ret"
}


sop() {
    local suffix=""
    if [ -n "$SIN" ]; then
        suffix=" < $SIN"
    fi
    if [ -n "$SOUT" ]; then
        suffix="$suffix > $SOUT"
    fi
    local missing=""
    if missing=$(skip_test "$@"); then
        printf "⛅ skipped [%s %s%s] due to missing inputs%s\n" \
               "$SOP" "$*" "$suffix" "$missing"
        SKIPCOUNT=$(( $SKIPCOUNT + 1 ))
        return
    fi
    printf "🔒 [%s %s%s]\n" "$SOP" "$*" "$suffix"
    if ! ( if [ -n "$SIN" ]; then exec < "$SIN"; fi;
           if [ -n "$SOUT" ]; then exec > "$SOUT"; fi;
           $SOP "$@") ; then
        printf "💣 Failed: %s%s\n" "$*" "$suffix"
        rm -f "$SOUT"
        ERRORS="$ERRORS
$*$suffix"
    else
        PASSCOUNT=$(( $PASSCOUNT + 1 ))
    fi
}

sop_fail() {
    local suffix=""
    if [ -n "$SIN" ]; then
        suffix=" < $SIN"
    fi
    if [ -n "$SOUT" ]; then
        printf 'ERROR: do not call sop_fail with expected stdout\n'
        exit 1
    fi
    local missing=""
    if missing=$(skip_test "$@"); then
        printf "⛅ skipped failing test [%s %s%s] due to %s%s\n" \
               "$SOP" "$*" "$suffix" "missing input" "$missing"
        SKIPCOUNT=$(( $SKIPCOUNT + 1 ))
        return
    fi
    printf "🔒⚠ [%s %s%s]\n" "$SOP" "$*" "$suffix"
    if ( if [ -n "$SIN" ]; then exec < "$SIN"; fi; $SOP "$@"); then
        printf >&2 "💣 succeeded when it should have failed: %s%s\n" \
               "$*" "$suffix"
        ERRORS="$ERRORS
! $*$suffix"
    else
        PASSCOUNT=$(( $PASSCOUNT + 1 ))
    fi
}

compare() {
    local args=""
    if [ "$1" = text -o "$1" = clearsigned ]; then
        args=--ignore-trailing-space
    fi
    comptype="$1"
    shift
    if ! [ -r "$1" -a -r "$2" ]; then
        printf "⛅ skipped %s comparison (%s) of %s and %s\n" \
               "missing inputs" "$comptype" "$1" "$2"
        SKIPCOUNT=$(( $SKIPCOUNT + 1 ))
        return
    fi
    if diff --unified $args "$1" "$2"; then
        printf "👍 %s and %s match!\n" "$1" "$2"
        PASSCOUNT=$(( $PASSCOUNT + 1 ))
    else
        printf " 💣 %s and %s do not match!\n" "$1" "$2"
        ERRORS="$ERRORS
Mismatch ($*)"
    fi
}

show_errs() {
    if [ -z "$1" ]; then
        if [ 0 -ne $SKIPCOUNT ]; then
            printf "No errors, but %d tests skipped somehow\n" \
                   $SKIPCOUNT
        else
            printf "No errors!\n"
        fi
    else
        local SKIPMSG=''
        if [ 0 -ne $SKIPCOUNT ]; then
            SKIPMSG=$(printf "%d tests skipped due to prior errors" \
                             $SKIPCOUNT)
        fi
        cat <<EOF

$PASSCOUNT tests passed.
$SKIPMSG

=== ERRORS ===
$1

=== Error summary ===
EOF
        E=$(echo "$1" | grep -v '^$')
        printf "%d Errors:\n" $(echo "$E" | wc -l)
        echo "$E" | sed 's/^! //' | cut -f1 -d\  | sort | uniq -c
    fi
}

DEARMORED=""

dearmor() {
    SIN="$1" SOUT="$1.bin" sop dearmor
    DEARMORED="$DEARMORED $1.bin"
}

ERRORS=""
SKIPCOUNT=0
PASSCOUNT=0
WORKDIR=$(mktemp -d)
printf "Working in: %s\n" "$WORKDIR"
cd "$WORKDIR"

sop version
sop version --extended
sop version --backend
sop version --sop-spec
sop version --sopv

sop list-profiles generate-key
sop list-profiles encrypt

SOUT=test.key sop generate-key "Example User <user@example.net>"
dearmor test.key
SIN=test.key SOUT=test.cert sop extract-cert
dearmor test.cert

SOUT=zeina.key sop generate-key "Zeina <zeina@example.net>"
dearmor zeina.key
SIN=zeina.key SOUT=zeina.cert sop extract-cert
dearmor zeina.cert

for f in cert key; do
    cat zeina.$f.bin test.$f.bin > both.$f.bin
    SIN=both.$f.bin SOUT=both.$f sop armor
done

SIN=test.key SOUT=test-revoked.cert sop revoke-key
dearmor test-revoked.cert

echo b4n4n4s > pw-orig.txt
SIN=test.key SOUT=test-locked.key sop change-key-password \
                   --new-key-password=pw-orig.txt
dearmor test-locked.key

# ensure that the key password is based on content, not filename
mv pw-orig.txt pw.txt
echo no-bananas > wrong-pw.txt

SIN=test-locked.key sop_fail change-key-password \
                          --old-key-password=wrong-pw.txt

SIN=test-locked.key SOUT=test-unlocked.key sop change-key-password \
                    --old-key-password=pw.txt
dearmor test-unlocked.key
compare binary test.key.bin test-unlocked.key.bin

cat > test.txt <<EOF
This is a test message.

We all ♥ OpenPGP!
EOF

for as in '' binary text; do
    asarg=''
    if [ -n "$as" ]; then
        asarg=--as=$as
    fi
    SIN=test.txt SOUT=test.$as.sig sop sign $asarg test.key
    dearmor test.$as.sig
    # should fail because no password is supplied.
    SIN=test.txt sop_fail sign $asarg test-locked.key

    # should fail because wrong password is supplied.
    SIN=test.txt sop_fail sign $asarg \
                 --with-key-password=wrong-pw.txt test-locked.key
    SIN=test.txt SOUT=test.$as.siglocked sop sign $asarg \
                 --with-key-password=pw.txt test-locked.key
    dearmor test.$as.siglocked

    for sig in test.$as.sig test.$as.sig.bin test.$as.siglocked \
                            test.$as.siglocked.bin; do
        for cert in test.cert test.cert.bin \
                              both.cert both.cert.bin; do
            SIN=test.txt sop verify $sig $cert
        done
        for cert in test-revoked.cert test-revoked.cert.bin; do
            SIN=test.txt sop_fail verify $sig $cert
        done
    done
done

for as in '' binary text clearsigned; do
    asarg=''
    cmparg=binary
    if [ -n "$as" ]; then
        asarg=--as=$as
        cmparg=$as
    fi
    SIN=test.txt SOUT=test.$as.signed sop inline-sign $asarg test.key
    msgs=test.$as.signed
    if [ "$as" != clearsigned ]; then
        dearmor test.$as.signed
        msgs="$msgs test.$as.signed.bin"
    fi
    for msg in $msgs; do
        SIN=$msg SOUT=$msg.body sop inline-detach \
                 --signatures-out=$msg.detached-sigs
        compare $cmparg test.txt $msg.body
        for cert in test.cert test.cert.bin both.cert \
                              both.cert.bin; do
                SIN=$msg SOUT=$msg.$cert.verified.txt sop \
                         inline-verify $cert
                compare $cmparg test.txt $msg.$cert.verified.txt
                SIN=$msg.body sop verify $msg.detached-sigs $cert
        done
        for cert in test-revoked.cert test-revoked.cert.bin; do
            SIN=$msg sop_fail inline-verify $cert
        done
    done
done

SIN=test.txt SOUT=test.msg sop encrypt test.cert
dearmor test.msg
SIN=test.txt SOUT=test.both.msg sop encrypt both.cert.bin
dearmor test.both.msg

for msg in test.msg test.msg.bin test.both.msg test.both.msg.bin; do
    SIN=$msg SOUT=$msg.decrypted.txt sop decrypt test.key
    compare binary test.txt $msg.decrypted.txt

    SIN=$msg sop_fail decrypt test-locked.key
    SIN=$msg sop_fail decrypt --with-key-password=wrong-pw.txt \
             test-locked.key
    SIN=$msg SOUT=$msg.locked-decrypted.txt sop decrypt \
             --with-key-password=pw.txt test-locked.key
    compare binary test.txt $msg.decrypted.txt
done

for x in $DEARMORED ; do
    SIN=$x SOUT=$x.asc sop armor
    SIN=$x.asc SOUT=$x.asc.bin sop dearmor
    compare binary $x $x.asc.bin
done

# TODO (subcommands still untested):

# merge-certs
# update-key
# certify-userid
# validate-userid

# TODO (sop features still untested):

# symmetric encryption/decryption (with password)
# using --no-armor explicitly
# sop generate-key --signing-only
# sop generate-key --with-key-password
# sop revoke-key --with-key-password
# using the -- delimiter between options and positional args
# sop sign --micalg-out
# signing and encrypting at the same time
# decrypting and verifying at the same time
# using profiles
# using session keys
# using date ranges
# using special designators (@FD: and @ENV:)
# using piped input instead of material in the filesystem
# confirming error codes for expected failures
# put multiple TSKs in a KEYS object
# sop_fail when KEYS is offered where CERTS should be
# sop_fail when CERTS are offered where KEYS should be

# This script does not test different algorithms or protocol-layer
# subtleties For more complete testing, see the OpenPGP
# Interoperability Test Suite, at https://tests.sequoia-pgp.org/

show_errs "$ERRORS"
if [ -d "$WORKDIR" ]; then
    rm -rf "$WORKDIR"
fi
]]></sourcecode></figure>

</section>
<section anchor="sopv-subset-test"><name>Testing the <spanx style="verb">sopv</spanx> Subset</name>

<t>The following two POSIX-compliant shell scripts can be used (with a signing-capable <spanx style="verb">sop</spanx> implementation) to exhaustively test a <spanx style="verb">sopv</spanx> implementation.</t>

<t>First, use <spanx style="verb">setup-sopv-test</spanx> with a signing-capable <spanx style="verb">sop</spanx> implementation to generate a set of test vectors in the current working directory.
Then, run <spanx style="verb">sopv-test</spanx> against the <spanx style="verb">sopv</spanx> implementation:</t>

<figure><artwork><![CDATA[
./setup-sopv-test some-sop
./sopv-test my-sopv
]]></artwork></figure>

<section anchor="setup-sopv-test"><name><spanx style="verb">setup-sopv-test</spanx></name>

<figure><sourcecode type="text/x-sh" name="setup-sopv-test"><![CDATA[
#!/bin/sh

# Create a-test environment for sopv: Stateless OpenPGP
# implementation Verification-only subset.  This needs a
# signing-capable SOP implementation to work.

# https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/

# Author: Daniel Kahn Gillmor
# License: CC-0

set -e

unset USE_DEFAULT_PROFILES
if [ "$1" = "--default-profile" ]; then
    USE_DEFAULT_PROFILES=true
    shift
fi

SOP=$1

if [ -z "$SOP" ]; then
    cat >&2 <<EOF
Usage: $0 [--default-profile] [--clean|SOP]

SOP should refer (either by \$PATH or by absolute path) to an
implementation of the Stateless OpenPGP command-line interface.

https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/

This will build a list of files in the current directory which can
be used with ./test-sopv to confirm support for the sopv subset.

If --clean is provided, destroy the list of files for testing sopv.

Normally, the default generate-key profile will be used for Alice,
and the second listed profile will be used for Bob.  If
--default-profile is provided, the default profile will be used for
both Alice and Bob.
EOF
    exit 1
fi

objs() {
   for s in .bin ''; do
       printf "%s\n" alice.cert$s bob.cert$s both.cert$s
       for m in text binary; do
           for u in alice bob both; do
               for o in sig inlinesigned; do
                   printf "%s\n" msg.$m.$u.$o$s
               done
           done
       done
   done
   for u in alice bob both; do
       printf "%s\n" msg.text.$u.csf
   done
   printf "%s\n" msg.text msg.binary alice.key bob.key
   printf "%s\n" expired.cert valid-from-expired.sig
   printf "%s\n" invalid-from-expired.sig timetravel-expired.sig
   printf "%s\n" baseline.cert baseline.sig baseline-revoked.cert
}

if [ "$SOP" = --clean ]; then
    rm -f $(objs)
    exit 0
fi

sop() {
    "$SOP" "$@"
}

# generate a high-entropy OpenPGP padding packet of overall length N
padding() {
    local n=$1
    if [ $n -le 194 ]; then
        n=$(( n - 2 ))
        printf '\325\'$(printf '%03o' $n )
    elif [ $n -gt 194 -a  $n -le 8386 ]; then
        n=$(( n - 3 ))
        printf '\325\'$(printf '%03o' $(( $n / 256 + 192 )) )'\'$(printf '%03o' $(( $n % 256 - 192 )) )
    else
        n=$(( n - 6 ))
        printf '\325\377\'$(printf '%03o' $(( n >> 24 )) )'\'$(printf '%03o' $(( (n >> 16) & 0xff )) )
        printf '\'$(printf '%03o' $(( (n >> 8) & 0xff  )) )'\'$(printf '%03o' $(( n  & 0xff )) )
    fi
    head -c $n < /dev/urandom
}

# use the first two profiles for the keys, reusing the default
# if zero or one exists
if [ "$USE_DEFAULT_PROFILES" = "true" ]; then
    profiles=$(echo default && echo default)
else
    profiles=$(sop list-profiles generate-key | cut -f1 -d: && \
                   echo default && echo default)
fi
profile_line=1

for uid in alice bob; do
    profile=$(printf "%s\n" "$profiles" | sed -n ${profile_line}p)
    profile_line=$(( $profile_line + 1 ))
    if [ "$profile" = default ]; then
        profile=
    else
        profile=--profile=$profile
    fi
    sop generate-key --signing-only $profile "$uid" \
        > "$uid.key"
    sop extract-cert < "$uid.key" > "$uid.cert"
    sop dearmor < "$uid.cert" > "$uid.cert.bin"
done

cat alice.cert.bin bob.cert.bin > both.cert.bin
sop armor < both.cert.bin > both.cert

cat > msg.text <<EOF
This is the signed message for the sopv test suite.

It should test the following things:

- Messages using the cleartext signing framework (CSF)
- Text-based signatures (armored and non-armored)
- Binary data signatures (armored and non-armored)
- Multiple certificates per CERTS or INLINESIGNED
- Unknown signatures in a CERTS
- @ENV as CERTS or SIGNATURES input
- @FD as CERTS or SIGNATURES input
- @FD as --verifications-out
- UTF-8 data (💣)
- Armored and non-armored OpenPGP certificates

Please confirm!
EOF

base64 -d > msg.binary <<EOF
AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v
MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f
YFNPUFYgaXMgdGhlIFN0YXRlbGVzcyBPcGVuUEdQIFZlcmlmaWNhdGlvbiBTdWJz
ZXTimaVhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqL
jI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7
vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err
7O3u7/Dx8vP09fb3+Pn6+/z9/v8=
EOF

# generated by ./generate-sopv-test-static-objects
cat > expired.cert <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEXgvhABYJKwYBBAHaRw8BAQdAsaTsNjmaCYylGOk6y3ZghkilgqGY7Nl7XFl2
LSRSUizNFHRoaXMgY2VydCBpcyBleHBpcmVkwoEEExYIACkFgl4L4QAFCQWkl6AC
mwMCHgAWIQT+ZY0dgTiHcdLO/cnxYLD0zfFAiQAKCRDxYLD0zfFAiYtKAQChYiLC
snvVV3AZUtDIFfSPG6PqqYuTFy0CzwFgAJR6cAD6AjcVWXsOWA6PlsZ4jmoWRWDW
/XQNIGrO5KPK4K4FtQ0=
=uQei
-----END PGP PUBLIC KEY BLOCK-----
EOF

cat > valid-from-expired.sig <<EOF
-----BEGIN PGP SIGNATURE-----

wnUEABYIAB0FgmHO8MAWIQT+ZY0dgTiHcdLO/cnxYLD0zfFAiQAKCRDxYLD0zfFA
iQ+eAP42je5wvtCN4Kfqub1bEhMi1EkioJgAWMcvE0Efa+47fgD9HYe/syBCXQWY
ARbV0lOfTMDwliWs5wPZupuOsBOryAs=
=TUXj
-----END PGP SIGNATURE-----
EOF

cat > invalid-from-expired.sig <<EOF
-----BEGIN PGP SIGNATURE-----

wnUEABYIAB0FgmWSAIAWIQT+ZY0dgTiHcdLO/cnxYLD0zfFAiQAKCRDxYLD0zfFA
iT0jAP9ZZt9UqI4PZtIiiYsXiJ55vT/54KFTnJ1xrrRxMLyeSwEAqwFfzXvpfXS5
eKVJcMG89qIkczZII32Ya+5kbU0JsQg=
=b9rH
-----END PGP SIGNATURE-----
EOF

cat > timetravel-expired.sig <<EOF
-----BEGIN PGP SIGNATURE-----

wnUEABYIAB0FglwqWSAWIQT+ZY0dgTiHcdLO/cnxYLD0zfFAiQAKCRDxYLD0zfFA
iWAAAP4tTANTYA6b+9m2UDEy7WhY0Q7IlBXz3Ppjuwf4i9LxJAD/epSvE8lVFHQI
w1vQvheqmIa3JOLhNDen3Wv85SwT4wo=
=zrLP
-----END PGP SIGNATURE-----
EOF

cat > baseline.cert <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEXgvhABYJKwYBBAHaRw8BAQdArUiK8psA3U3Q8mdO1DZR2UW8XgXBB3VVtHaj
r1UaUFfNJWJhc2VsaW5lIGNlcnRpZmljYXRlLCB3aWxsIGJlIHJldm9rZWTCewQT
FggAIwWCXgvhAAKbAwIeABYhBHGqmGkigo5sDdKjgjk1BkEkKnCVAAoJEDk1BkEk
KnCVUNcBANRfAasPy5lXXFXskfX4yyFx1M1kxX17vxoQEDtB6TrqAQCTyzV4vjUm
Y3tgljlN8iZZd1aJEDaHYY6thPKqE0UACg==
=WsIg
-----END PGP PUBLIC KEY BLOCK-----
EOF

cat > baseline.sig <<EOF
-----BEGIN PGP SIGNATURE-----

wnUEABYIAB0FgmfUYiwWIQRxqphpIoKObA3So4I5NQZBJCpwlQAKCRA5NQZBJCpw
lfW7AQD+/Oc8y6Vgij/CSgZm+Bg74ezJ91K6fCSKlgMsXc/g5AEAv7/kLe1Gdu5u
IA26te6ytPfJAUoiI/Tyw5YYV+CgRQo=
=obH5
-----END PGP SIGNATURE-----
EOF

cat > baseline-revoked.cert <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEXgvhABYJKwYBBAHaRw8BAQdArUiK8psA3U3Q8mdO1DZR2UW8XgXBB3VVtHaj
r1UaUFfCeAQgFggAIAWCYc7wwAIdABYhBHGqmGkigo5sDdKjgjk1BkEkKnCVAAoJ
EDk1BkEkKnCVwgEA/RAFHGWHBjgEvthbeV13/fdrfSC+5RrrvF50a2haXBuEAQD/
Z2U5Eg/ka5LrjdPLyZfE2+j7+boVD8dQq2b0g8+0D80lYmFzZWxpbmUgY2VydGlm
aWNhdGUsIHdpbGwgYmUgcmV2b2tlZMJ7BBMWCAAjBYJeC+EAApsDAh4AFiEEcaqY
aSKCjmwN0qOCOTUGQSQqcJUACgkQOTUGQSQqcJVQ1wEA1F8Bqw/LmVdcVeyR9fjL
IXHUzWTFfXu/GhAQO0HpOuoBAJPLNXi+NSZje2CWOU3yJll3VokQNodhjq2E8qoT
RQAK
=J9fE
-----END PGP PUBLIC KEY BLOCK-----
EOF


for signer in alice bob; do 
    for form in text binary; do
        sop sign --as=$form $signer.key < msg.$form \
            > msg.$form.$signer.sig
        sop dearmor < msg.$form.$signer.sig \
            > msg.$form.$signer.sig.bin
        sop inline-sign --as=$form $signer.key < msg.$form \
            > msg.$form.$signer.inlinesigned
        sop dearmor < msg.$form.$signer.inlinesigned \
            > msg.$form.$signer.inlinesigned.bin
        (cat msg.$form.$signer.sig.bin && padding 20) \
            > msg.$form.$signer.sig.postpadded
        (padding 234 && cat msg.$form.$signer.sig.bin) \
            > msg.$form.$signer.sig.prepadded
    done
    sop inline-sign --as=clearsigned $signer.key < msg.text \
        > msg.text.$signer.csf
done

for form in text binary; do
    sop sign --as=$form alice.key bob.key < msg.$form \
        > msg.$form.both.sig
    sop dearmor < msg.$form.both.sig > msg.$form.both.sig.bin
    (cat msg.$form.both.sig.bin && padding 192) \
        > msg.$form.both.sig.postpadded
    (padding 15 && cat msg.$form.both.sig.bin) \
        > msg.$form.both.sig.prepadded
    sop inline-sign --as=$form alice.key bob.key < msg.$form \
        > msg.$form.both.inlinesigned
    sop dearmor < msg.$form.both.inlinesigned \
        > msg.$form.both.inlinesigned.bin
done
sop inline-sign --as=clearsigned alice.key bob.key \
    < msg.text > msg.text.both.csf

if ! ls $(objs) > /dev/null; then
    exit 1
fi
]]></sourcecode></figure>

</section>
<section anchor="sopv-test"><name><spanx style="verb">sopv-test</spanx></name>

<figure><sourcecode type="text/x-sh" name="sopv-test"><![CDATA[
#!/bin/sh

# Test the Stateless OpenPGP implementation Verification-only subset.

# This needs to be run from within a directory created by the
#  setup-sopv-test script.

# https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/

# Author: Daniel Kahn Gillmor
# License: CC-0

SOPV=$1

if [ -z "$SOPV" ]; then
    cat >&2 <<EOF
Usage: $0 SOPV

SOPV should refer (either by \$PATH or by absolute path) to an
implementation of the Stateless OpenPGP Verification-only subset.
See https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/
EOF
    exit 1
fi

sopv() {
    local suffix=""
    if [ -n "$SIN" ]; then
        suffix=" < $SIN"
    fi
    if [ -n "$SOUT" ]; then
        suffix="$suffix > $SOUT"
    fi
    if [ -n "$FD_3" ]; then
        suffix="$suffix 3< $FD_3"
    fi
    if [ -n "$FD_4" ]; then
        suffix="$suffix 4< $FD_4"
    fi
    if [ -n "$FD_5" ]; then
        suffix="$suffix 5< $FD_5"
    fi
    # FD 9 is used for output, not input
    if [ -n "$FD_9" ]; then
        suffix="$suffix 9> $FD_9"
    fi
    local missing=""
    printf "🔒 [%s %s%s]\n" "$SOPV" "$*" "$suffix"
    if ! ( if [ -n "$SIN" ]; then exec < "$SIN"; fi;
           if [ -n "$SOUT" ]; then exec > "$SOUT"; fi;
           if [ -n "$FD_3" ]; then exec 3< "$FD_3"; fi;
           if [ -n "$FD_4" ]; then exec 4< "$FD_4"; fi;
           if [ -n "$FD_5" ]; then exec 5< "$FD_5"; fi;
           if [ -n "$FD_9" ]; then exec 9> "$FD_9"; fi;
           $SOPV "$@") ; then
        printf "💣 Failed: %s%s\n" "$*" "$suffix"
        rm -f "$SOUT"
        ERRORS="$ERRORS
$*$suffix"
        return 1
    else
        PASSCOUNT=$(( $PASSCOUNT + 1 ))
        return 0
    fi
}

sopv_fail() {
    local suffix=""
    if [ -n "$SIN" ]; then
        suffix=" < $SIN"
    fi
    if [ -n "$SOUT" ]; then
        printf 'ERROR: do not call sopv_fail and expect stdout\n'
        exit 1
    fi
    if [ -n "$FD_3" ]; then
        suffix="$suffix 3< $FD_3"
    fi
    if [ -n "$FD_4" ]; then
        suffix="$suffix 4< $FD_4"
    fi
    if [ -n "$FD_5" ]; then
        suffix="$suffix 5< $FD_5"
    fi
    # FD 9 is used for output, not input
    if [ -n "$FD_9" ]; then
        suffix="$suffix 9> $FD_9"
    fi
    local missing=""
    printf "🔒⚠ [%s %s%s]\n" "$SOPV" "$*" "$suffix"
    if ( if [ -n "$SIN" ]; then exec < "$SIN"; fi;
         if [ -n "$FD_3" ]; then exec 3< "$FD_3"; fi;
         if [ -n "$FD_4" ]; then exec 4< "$FD_4"; fi;
         if [ -n "$FD_5" ]; then exec 5< "$FD_5"; fi;
         if [ -n "$FD_9" ]; then exec 9> "$FD_9"; fi;
         $SOPV "$@" > fail.out); then
        printf >&2 "💣 succeeded when it should have failed: %s%s\n" \
               "$*" "$suffix"
        ERRORS="$ERRORS
! $*$suffix"
    else
        if [ -s fail.out ]; then
            printf >&2 "💣 produced material to stdout: %s%s\n" \
                   "$*" "$suffix"
            sed 's/^/ 💣> /' < fail.out >&2
            ERRORS="$ERRORS
! $*$suffix ⚠PRODUCED OUTPUT⚠"
        else
            PASSCOUNT=$(( $PASSCOUNT + 1 ))
        fi
    fi
    rm -f fail.out
}

compare() {
    local args=""
    if [ "$1" = text -o "$1" = clearsigned ]; then
        args=--ignore-trailing-space
    fi
    comptype="$1"
    shift
    if ! [ -r "$1" -a -r "$2" ]; then
        printf "⛅ skipped %s cmp (missing inputs): %s and %s\n" \
               "$comptype" "$1" "$2"
        SKIPCOUNT=$(( $SKIPCOUNT + 1 ))
        return
    fi
    if diff --unified $args "$1" "$2"; then
        printf "👍 %s and %s match!\n" "$1" "$2"
        PASSCOUNT=$(( $PASSCOUNT + 1 ))
    else
        printf " 💣 %s and %s do not match!\n" "$1" "$2"
        ERRORS="$ERRORS
Mismatch ($*)"
    fi
}

reject_output() {
    for f in "$@"; do
        if [ -s "$f" ]; then
            printf "💣 %s should not exist with content!\n" "$f"
            ERRORS="$ERRORS
Should-not-exist $f"
        else
            PASSCOUNT=$(( $PASSCOUNT + 1 ))
        fi
    done
}

confirm_mode() {
    local foundmode=''
    for m in $(cut -f4 -d\  < "$2"); do
        if [ "$m" != "mode:$1" ]; then
            printf "💣 %s should have mentioned mode:%s, was %s!\n" \
                   "$2" "$1" "$m"
            ERRORS="$ERRORS
VERIFICATIONS-bad-mode $2 (was: $m; wanted mode:$1)"
        else
            foundmode=yes
        fi
    done
    if [ -z "$foundmode" ]; then
            printf "💣 %s had no mode, wanted %s!\n" "$2" "$1"
            ERRORS="$ERRORS
VERIFICATIONS-no-mode $2 (wanted mode:$1)"
    else
        PASSCOUNT=$(( $PASSCOUNT + 1 ))
    fi
}

show_errs() {
    if [ -z "$1" ]; then
        if [ 0 -ne $SKIPCOUNT ]; then
            printf "No errors, %d tests passed.\n"
            printf "but %d tests skipped somehow\n" \
                   $PASSCOUNT $SKIPCOUNT
        else
            printf "No errors! %d tests passed\n" $PASSCOUNT
        fi
    else
        local SKIPMSG=''
        if [ 0 -ne $SKIPCOUNT ]; then
            SKIPMSG=$(printf "%d tests skipped due to prior errors" \
                             $SKIPCOUNT)
        fi
        cat <<EOF

$PASSCOUNT tests passed.
$SKIPMSG

=== ERRORS ===
$1

=== Error summary ===
EOF
        E=$(echo "$1" | grep -v '^$')
        printf "%d Errors:\n" $(echo "$E" | wc -l)
        echo "$E" | sed 's/^! //' | cut -f1 -d\  | sort | uniq -c
    fi
}


ERRORS=""
SKIPCOUNT=0
PASSCOUNT=0

combine() {
    # runners take: sopv|sopv_fail signer cert [cert...]
    local runner=$1
    shift
    $runner sopv alice alice.$cert
    $runner sopv bob bob.$cert
    $runner sopv_fail bob alice.$cert
    $runner sopv_fail alice bob.$cert
    $runner sopv both alice.$cert
    $runner sopv both bob.$cert
    $runner sopv both both.$cert
    $runner sopv alice both.$cert
    $runner sopv bob both.$cert
    $runner sopv alice alice.$cert bob.$cert
    $runner sopv alice bob.$cert alice.$cert
    $runner sopv bob alice.$cert bob.$cert
    $runner sopv bob bob.$cert alice.$cert
    FD_3=alice.$cert $runner sopv alice @FD:3
    FD_3=bob.$cert FD_4=alice.$cert $runner sopv alice @FD:3 @FD:4
    # don't try to test @ENV on non-armored certs
    if [ "$cert" = "cert" ]; then
        SIGNER_CERT=$(cat alice.$cert) $runner sopv \
                   alice @ENV:SIGNER_CERT
    fi
}

detached() {
    local sopv=$1
    shift
    local signer=$1
    shift
    SIN=msg.$form $sopv verify $delim msg.$form.$signer.$sig "$@"
    FD_5=msg.$form.$signer.$sig SIN=msg.$form $sopv verify $delim \
                                @FD:5 "$@"
    # don't try to test @ENV on non-armored signatures
    if [ "$sig" = "sig" ]; then
        SIGNATURE=$(cat msg.$form.$signer.$sig) SIN=msg.$form $sopv \
                 verify $delim @ENV:SIGNATURE "$@"
    fi
}

inlinesigned() {
    local sopv=$1
    shift
    local signer=$1
    shift
    local vout=msg.$form.$signer.$inlmsg.verifs
    rm -f "$vout"
    if [ "$sopv" = sopv ]; then
        if SIN=msg.$form.$signer.$inlmsg \
               SOUT=msg.$form.$signer.$inlmsg.out $sopv \
               inline-verify --verifications-out=$vout \
               $delim "$@" ; then
            confirm_mode "$form" "$vout"
        fi
        if FD_9=$vout.fd SIN=msg.$form.$signer.$inlmsg \
                         SOUT=msg.$form.$signer.$inlmsg.out.fd \
                         $sopv inline-verify \
                         --verifications-out=@FD:9 \
                         $delim "$@" ; then
            confirm_mode "$form" "$vout.fd"
        fi
        compare $form msg.$form msg.$form.$signer.$inlmsg.out
        compare binary msg.$form.$signer.$inlmsg.out \
                msg.$form.$signer.$inlmsg.out.fd
        rm -f msg.$form.$signer.$inlmsg.out $vout \
           msg.$form.$signer.$inlmsg.out.fd $vout.fd

        # inlinesigned msgs can't be used as detached signatures:
        SIN=msg.$form sopv_fail verify $delim \
                      msg.$form.$signer.$inlmsg "$@"

    else
        SIN=msg.$form.$signer.$inlmsg $sopv inline-verify \
                                      --verifications-out=$vout \
                                      $delim "$@"
        FD_9=$vout.fd SIN=msg.$form.$signer.$inlmsg $sopv \
                      inline-verify --verifications-out=@FD:9 \
                      $delim "$@"
        reject_output $vout $vout.fd
    fi
}

sopv version --extended
sopv version --sopv

for delim in '' --; do
    for cert in cert cert.bin; do
        for form in binary text; do
            # test detached signature
            for sig in sig sig.bin sig.prepadded sig.postpadded; do
                combine detached
            done

            # test inline-signed messages
            for inlmsg in inlinesigned inlinesigned.bin; do
                combine inlinesigned
            done
        done

        # test CSF
        form=text inlmsg=csf combine inlinesigned
    done
done

sopv verify valid-from-expired.sig expired.cert < msg.binary
sopv_fail verify invalid-from-expired.sig expired.cert < msg.binary
sopv_fail verify timetravel-expired.sig expired.cert < msg.binary

sopv verify baseline.sig baseline.cert < msg.binary
sopv_fail verify baseline.sig baseline-revoked.cert < msg.binary

# FIXME:
#
# - --not-before and --not-after
# - JSON extension to VERIFICATIONS, including "signers" (sopv 1.1)
# - using --argument=foo vs. --argument foo ?
# - review equivalence of VERIFICATIONS
# - confirm failure when --verifications-out already exists
# - passing CERTS where SIGNATURES are expected MUST fail
# - passing KEYS where CERTS are expected MUST fail

show_errs "$ERRORS"

# Succeed only if $ERRORS is empty:
[ -z "$ERRORS" ]
]]></sourcecode></figure>

</section>
</section>
<section anchor="acknowledgements"><name>Acknowledgements</name>

<t>This work was inspired by Justus Winter's <xref target="OpenPGP-Interoperability-Test-Suite"/>.</t>

<t>The following people contributed helpful feedback and considerations to this draft, but are not responsible for its problems:</t>

<t><list style="symbols">
  <t>Allan Nordhøy</t>
  <t>Antoine Beaupré</t>
  <t>Edwin Taylor</t>
  <t>Guillem Jover</t>
  <t>Heiko Schaefer</t>
  <t>Jameson Rollins</t>
  <t>Justus Winter</t>
  <t>Paul Schaub</t>
  <t>Vincent Breitmoser</t>
</list></t>

</section>
<section anchor="future-work"><name>Future Work</name>

<t><list style="symbols">
  <t>certificate transformation into popular publication forms:
  <list style="symbols">
      <t>WKD</t>
      <t>DANE OPENPGPKEY</t>
      <t>Autocrypt</t>
    </list></t>
  <t><spanx style="verb">sop encrypt</spanx> -- specify compression? (see <xref target="compression"/>)</t>
  <t><spanx style="verb">sop encrypt</spanx> -- specify padding policy/mechanism?</t>
  <t><spanx style="verb">sop decrypt</spanx> -- how can it more safely handle zip bombs?</t>
  <t><spanx style="verb">sop decrypt</spanx> -- what should it do when encountering weakly-encrypted (or unencrypted) input?</t>
  <t><spanx style="verb">sop encrypt</spanx> -- minimize metadata (e.g., <spanx style="verb">--throw-keyids</spanx>)?</t>
  <t>specify an error if a <spanx style="verb">DATE</spanx> arrives as input without a time zone?</t>
  <t>add considerations about what it means for armored <spanx style="verb">CERTS</spanx> to contain multiple certificates -- multiple armorings?  one big blob?</t>
  <t>do we need an interface or option (for performance?) with the semantics that <spanx style="verb">sop</spanx> doesn't validate certificates internally, it just accepts whatever's given as legit data? (see <xref target="cert-validity-performance"/>)</t>
  <t>do we need to be able to convert a message with a text-based signature to a CSF <spanx style="verb">INLINESIGNED</spanx> message? I'd rather not, given the additional complications.</t>
  <t>add encryption and decryption to C Library API</t>
</list></t>

</section>
<section anchor="document-history"><name>Document History</name>

<section anchor="substantive-changes-between-15-and-16"><name>Substantive Changes between -15 and -16:</name>

<t><list style="symbols">
  <t>add Daniel Huigens as co-author</t>
  <t>add pointer to <spanx style="verb">msop</spanx> implementation</t>
  <t>indicate that environment variables are allowed to influence sop</t>
  <t>clean up file extensions in examples</t>
</list></t>

</section>
<section anchor="substantive-changes-between-14-and-15"><name>Substantive Changes between -14 and -15:</name>

<t><list style="symbols">
  <t><spanx style="verb">update-key</spanx>: permit/encourage creation of replacement primary keys</t>
  <t><spanx style="verb">update-key</spanx>: add <spanx style="verb">--revoke-deprecated-keys</spanx></t>
  <t><spanx style="verb">encrypt</spanx>: add <spanx style="verb">--for={storage|communications|any}</spanx></t>
</list></t>

</section>
<section anchor="substantive-changes-between-13-and-14"><name>Substantive Changes between -13 and -14:</name>

<t><list style="symbols">
  <t>Improve <spanx style="verb">sopv</spanx> tests in <xref target="sopv-subset-test"/></t>
  <t>libsop C API: split out <spanx style="verb">sopv.h</spanx> from <spanx style="verb">sop.h</spanx></t>
  <t>libsop C API: use <spanx style="verb">int64_t</spanx> for <spanx style="verb">sop_time</spanx></t>
  <t>libsop C API: use <spanx style="verb">size_t</spanx> for counts</t>
  <t>Recommend emitting trailing newline when outputting <spanx style="verb">SESSIONKEY</spanx></t>
  <t><spanx style="verb">sopv</spanx> 1.0: note that <spanx style="verb">@ENV:</spanx> and <spanx style="verb">@FD:</spanx> also need to work for <spanx style="verb">SIGNATURES</spanx></t>
  <t>Define <spanx style="verb">sopv</spanx> 1.2: add <spanx style="verb">validate-userid</spanx></t>
</list></t>

</section>
<section anchor="substantive-changes-between-12-and-13"><name>Substantive Changes between -12 and -13:</name>

<t><list style="symbols">
  <t>Define <spanx style="verb">sopv</spanx> 1.1 (structured json VERIFICATIONS output)</t>
  <t>Fix misspellings</t>
</list></t>

</section>
<section anchor="substantive-changes-between-11-and-12"><name>Substantive Changes between -11 and -12:</name>

<t><list style="symbols">
  <t>Improvements in POSIX shell tests (including robust <spanx style="verb">sopv</spanx> test)</t>
  <t>Define <spanx style="verb">security</spanx>, <spanx style="verb">performance</spanx>, and <spanx style="verb">compatibility</spanx> profile aliases</t>
  <t>Clarify that <spanx style="verb">sop armor</spanx> ought to be able to armor any output that <spanx style="verb">sop</spanx> produces</t>
  <t>Intro: acknowledge increased attention to key/cert management</t>
  <t>Add <spanx style="verb">KEY_CANNOT_CERTIFY</spanx> error code</t>
  <t>Relax guidance on multi-signature operations and <spanx style="verb">--micalg-out</spanx></t>
  <t>Define <spanx style="verb">sopv</spanx> 1.0 (with changelog)</t>
  <t>Document exceptions to statelessness for system-level state</t>
</list></t>

</section>
<section anchor="substantive-changes-between-10-and-11"><name>Substantive Changes between -10 and -11:</name>

<t><list style="symbols">
  <t><spanx style="verb">update-key</spanx>: new key management subcommand</t>
  <t><spanx style="verb">merge-certs</spanx>: new certificate management subcommand</t>
  <t><spanx style="verb">certify-userid</spanx>: new User ID certification subcommand</t>
  <t><spanx style="verb">validate-userid</spanx>: new User ID verification subcommand</t>
  <t>Replace references to RFC 4880 with RFC 9580</t>
  <t>Set aside error 1 as <spanx style="verb">UNSPECIFIED_FAILURE</spanx></t>
  <t>Encourage JSON output in tail of <spanx style="verb">VERIFICATIONS</spanx> lines</t>
  <t>Add universal (ignorable) <spanx style="verb">--debug</spanx> option</t>
  <t>Add simple (and incomplete) shell-script test in appendix</t>
</list></t>

</section>
<section anchor="substantive-changes-between-09-and-10"><name>Substantive Changes between -09 and -10:</name>

<t><list style="symbols">
  <t>drop <spanx style="verb">@HARDWARE:</spanx> special designator in favor of the simple <xref target="I-D.dkg-openpgp-external-secrets"/> or other magic</t>
  <t>drop hardware-specific C API function</t>
  <t>define SemVer-versioned <spanx style="verb">sopv</spanx> subset of CLI</t>
  <t><spanx style="verb">sop version</spanx>: add <spanx style="verb">--sopv</spanx> option</t>
  <t>define libsopv subset of C API</t>
  <t>explicitly require <spanx style="verb">BAD_DATA</spanx> failure when <spanx style="verb">KEYS</spanx> are passed as <spanx style="verb">CERTS</spanx></t>
</list></t>

</section>
<section anchor="substantive-changes-between-08-and-09"><name>Substantive Changes between -08 and -09:</name>

<t><list style="symbols">
  <t>enable the use of hardware-backed secret key material via the <spanx style="verb">@HARDWARE:</spanx> special designator</t>
  <t>C API: clarify design goals and usage patterns</t>
  <t>C API: major overhaul and normalization:
  <list style="symbols">
      <t>allow passthrough "cookie" for logging</t>
      <t>allow NULL return from <spanx style="verb">sop_version_*</spanx></t>
      <t>explicitly offer <spanx style="verb">SOP_LOG_NEVER</spanx></t>
      <t>use <spanx style="verb">*_from_bytes</spanx> and <spanx style="verb">*_to_bytes</spanx> instead of <spanx style="verb">*_import</spanx> and <spanx style="verb">*_export</spanx></t>
      <t>datatype objects are now immutable</t>
      <t>operation objects are one-shot</t>
      <t>always return <spanx style="verb">sop_err</spanx>, even at a slight cost to C caller ergonomics</t>
    </list></t>
</list></t>

</section>
<section anchor="substantive-changes-between-07-and-08"><name>Substantive Changes between -07 and -08:</name>

<t><list style="symbols">
  <t><spanx style="verb">revoke-key</spanx>, <spanx style="verb">change-key-password</spanx>: add <spanx style="verb">--no-armor</spanx> option</t>
  <t><spanx style="verb">generate-key</spanx>: should fail on non-UTF-8 <spanx style="verb">USERID</spanx></t>
  <t><spanx style="verb">generate-key</spanx>: acknowledge that implementations <bcp14>MAY</bcp14> reject <spanx style="verb">USERID</spanx>s that seem bad</t>
  <t><spanx style="verb">armor</spanx>: drop <spanx style="verb">--label</spanx> option</t>
  <t><spanx style="verb">encrypt</spanx>: add <spanx style="verb">--session-key-out</spanx> option</t>
  <t>ASCII-armored objects should not be concatenated</t>
  <t>signature verification should only work for sigtypes 0x00 (binary) and 0x01 (canonical text)</t>
  <t><spanx style="verb">sign</spanx>: Constrain input when <spanx style="verb">--micalg-out</spanx> is present for alignment with <xref target="RFC3156"/></t>
  <t>propose simple C API for signing and verification</t>
</list></t>

</section>
<section anchor="substantive-changes-between-06-and-07"><name>Substantive Changes between -06 and -07:</name>

<t><list style="symbols">
  <t><spanx style="verb">generate-key</spanx>: add <spanx style="verb">--signing-only</spanx> option</t>
  <t>new key management subcommand: <spanx style="verb">change-key-password</spanx></t>
  <t>new key management subcommand: <spanx style="verb">revoke-key</spanx></t>
</list></t>

</section>
<section anchor="substantive-changes-between-05-and-06"><name>Substantive Changes between -05 and -06:</name>

<t><list style="symbols">
  <t><spanx style="verb">version</spanx>: add <spanx style="verb">--sop-spec</spanx> argument</t>
  <t><spanx style="verb">encrypt</spanx>: add <spanx style="verb">--profile</spanx> argument</t>
</list></t>

</section>
<section anchor="substantive-changes-between-04-and-05"><name>Substantive Changes between -04 and -05:</name>

<t><list style="symbols">
  <t><spanx style="verb">decrypt</spanx>: change <spanx style="verb">--verify-out</spanx> to <spanx style="verb">--verifications-out</spanx></t>
  <t><spanx style="verb">encrypt</spanx>: add missing <spanx style="verb">--with-key-password</spanx></t>
  <t>add the concept of "profiles", use with <spanx style="verb">generate-key</spanx></t>
  <t>include table of known implementations</t>
  <t><spanx style="verb">VERIFICATIONS</spanx> can now indicate the type of the signature (<spanx style="verb">mode:text</spanx> or <spanx style="verb">mode:binary</spanx>)</t>
</list></t>

</section>
<section anchor="substantive-changes-between-03-and-04"><name>Substantive Changes between -03 and -04:</name>

<t><list style="symbols">
  <t>Reinforce that PASSWORD and SESSIONKEY are indirect data types</t>
  <t><spanx style="verb">encrypt</spanx>: remove <spanx style="verb">--as=mime</spanx> option</t>
  <t>Handle password-locked secret key material: add <spanx style="verb">--with-key-password</spanx> options to <spanx style="verb">generate-key</spanx>, <spanx style="verb">sign</spanx>, and <spanx style="verb">decrypt</spanx>.</t>
  <t>Introduce <spanx style="verb">INLINESIGNED</spanx> message type (<xref target="inlinesigned"/>)</t>
  <t>Rename <spanx style="verb">detach-inband-signature-and-message</spanx> to <spanx style="verb">inline-detach</spanx>, clarify its possible inputs</t>
  <t>Add <spanx style="verb">inline-verify</spanx></t>
  <t>Add <spanx style="verb">inline-sign</spanx></t>
</list></t>

</section>
<section anchor="substantive-changes-between-02-and-03"><name>Substantive Changes between -02 and -03:</name>

<t><list style="symbols">
  <t>Added <spanx style="verb">--micalg-out</spanx> parameter to <spanx style="verb">sign</spanx></t>
  <t>Change from <spanx style="verb">KEY</spanx> to <spanx style="verb">KEYS</spanx> (permit multiple secret keys in each blob)</t>
  <t>New error code: <spanx style="verb">KEY_CANNOT_SIGN</spanx></t>
  <t><spanx style="verb">version</spanx> now has <spanx style="verb">--backend</spanx> and <spanx style="verb">--extended</spanx> options</t>
</list></t>

</section>
<section anchor="substantive-changes-between-01-and-02"><name>Substantive Changes between -01 and -02:</name>

<t><list style="symbols">
  <t>Added mnemonics for return codes</t>
  <t><spanx style="verb">decrypt</spanx> should fail when asked to output to a pre-existing file</t>
  <t>Removed superfluous <spanx style="verb">--armor</spanx> option</t>
  <t>Much more specific about what <spanx style="verb">armor --label=auto</spanx> should do</t>
  <t><spanx style="verb">armor</spanx> and <spanx style="verb">dearmor</spanx> are now fully idempotent, but work only well-formed OpenPGP streams</t>
  <t>Dropped <spanx style="verb">armor --allow-nested</spanx></t>
  <t>Specified what <spanx style="verb">encrypt --as=</spanx> means</t>
  <t>New error code: <spanx style="verb">KEY_IS_PROTECTED</spanx></t>
  <t>Documented expectations around human-readable, human-transferable passwords</t>
  <t>New subcommand: <spanx style="verb">detach-inband-signature-and-message</spanx></t>
  <t>More specific guidance about special designators like <spanx style="verb">@FD:</spanx> and <spanx style="verb">@ENV:</spanx>, including new error codes <spanx style="verb">UNSUPPORTED_SPECIAL_PREFIX</spanx> and <spanx style="verb">AMBIGUOUS_INPUT</spanx></t>
</list></t>

</section>
<section anchor="substantive-changes-between-00-and-01"><name>Substantive Changes between -00 and -01:</name>

<t><list style="symbols">
  <t>Changed <spanx style="verb">generate</spanx> subcommand to <spanx style="verb">generate-key</spanx></t>
  <t>Changed <spanx style="verb">convert</spanx> subcommand to <spanx style="verb">extract-cert</spanx></t>
  <t>Added "Input String Types" section as distinct from indirect I/O</t>
  <t>Made implicit arguments potentially explicit (e.g., <spanx style="verb">sop armor --label=auto</spanx>)</t>
  <t>Added <spanx style="verb">--allow-nested</spanx> to <spanx style="verb">sop armor</spanx> to make it idempotent by default</t>
  <t>Added fingerprint of signing (sub)key to <spanx style="verb">VERIFICATIONS</spanx> output</t>
  <t>Dropped <spanx style="verb">--mode</spanx> and <spanx style="verb">--session-key</spanx> arguments for <spanx style="verb">sop encrypt</spanx> (no plausible use, not needed for interop)</t>
  <t>Added <spanx style="verb">--with-session-key</spanx> argument to <spanx style="verb">sop decrypt</spanx> to allow for session-key-based decryption</t>
  <t>Added examples to each subcommand</t>
  <t>More detailed error codes for <spanx style="verb">sop encrypt</spanx></t>
  <t>Move from <spanx style="verb">CERT</spanx> to <spanx style="verb">CERTS</spanx> (each <spanx style="verb">CERTS</spanx> argument might contain multiple certificates)</t>
</list></t>

</section>
</section>


  </back>

<!-- ##markdown-source:
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
G/0AQ1Tzk/cMfkAKJJKdsIne7a/HS547e28vd8sgSdl7Db40sqf1EnbjXZBW
SMK0Xld2t/ZsGRLfbZY3Tt6SyPjHNyosL3WTaofNyzZGlcShGkjoSTpYkjaD
gMI8Hjyd9JL8OOacd57+lYWRUcsRGNDcPV3/z5mU6+u6Sd6TJx58l6DMT+6h
tZiFRi77Rp5kyPQzjpV+oEGCpydDOiXBK/pA5c2c8LX2zJvMN5rMd4xzLXc+
fBQUg1NYObjCcXl5Zn2l4TMRgD9bpSMYg76Ehg5iRg1RTTsCe9WJploFileg
zEZ5LHl5fNzIBqJa9HZPdnZyOl5EncG6aa259k+CG0hFd8M0nD/FQrASApSU
7X7GIy93vuazwW2phXK8RhUtZkbNLgk5wcAQQT515apVQxfSc88U2eAoZMdS
ES6ESX+osGdW6+cdggWKEFExY7dSj7yz1Oc9u000PeOqT1QLFQFhHUk01zZz
C9QdXKF/2khLXHgYRqW9pj289URFz70MnTd3ZblB6veYuRXF2ce8guV1GQj6
IUJ6l4EQHYp3FHnk17Pp85Q2YDwrY0aLP+qmIsekZVZJvV4UCnqtlAGoYyFG
gvSt7NeE9pMxMekSElUP2O45Ae2BNWEvCYWeCGQvMJRoOYXwA7B2gAkJ0Yuq
SUG7mhUst9N8LZs2QgmWqJod3zke6J7SCFrOPCL/URPDsH0DO/acablpNvSN
wBy6sZBSd35EQl56rySLakf2Ub27VLlTeol+egaIAHGcSJ+o+mvfZRqcSama
Nl413p6+8cA8FhobB1CggDWUL0Bltij+1Cx7c/54WqAhVVxQcmShvpLfVRtF
yijTNSTx87AvkAp0zXkVjMgKywzP40jlUo9RmrQB9QavE82wVfho0mqueLDe
HAaKJz8HyxLEt+M5CjK+g81Fp8h7kc2jUecqbGtgE1c3rbR0pZ1ykaKDsacM
T2ffvyMrhay1rNUtpja9vRqSth0FFQtN376Ux9Zgv2BaGBKoi3cb4nvF+l0F
taWk7ivlqCB5lZ06Tynuskp81lccqUzPiI7QzHFSJX9SP2GutPCIX4zwCE/e
M/gLtx+QzS4HOg2JanNMFbGU/HIIW+8rOAE901nYZy81C08IuTbLyeE1D7zM
maVSwPNKuy1mAWHDPv6XHMttB6Zmnw0bMJBNluNu13jd0vGToJGMg4ovSn9j
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
yHHSvemGd127AlLpUHr4jjomvL7T+a0QwKRqwjRbm1MmyeUcF1zSveUE4I/j
kaOFJPakmN7JVKywTEb82US0F+sDHOwXK6hM+dmWg5hEisVyqXh3sLXRrFVK
B+HOZrGwt3lfPCxffzjZOrw4f7tx47+9v6u/u37VrBxVPr8vnXTej5q97VYU
7Ryt3GY+bJZHH74eLO5+rq3sHYcv9zcLz/cLGxsHN7vlw5OP747K7e2jwv3u
8c3awcnp++PTrdOz08Xrj2ftQe38dLWRudja3T/Zumj65x+a9bfX7crWbuHi
/LB99fb0a220sV97ezo8KdcPKlsf27VOu+Of7V7X37Zvr1obx/Wz918zH8+P
Wx3/9Pqis3vz8exj13/b/uIv3Q+uOmt3tfP3X+vvTpfqy9erIL+8apyvLjQr
b0vNlaOt6zCotC6+7GQ+V5b2Pq+WDm96eyftj/55533H76yO6t3e82bob3/u
bZ91ei9avS9fhlHff3Eb7bwdRS+PFgf9YGV49eVl5nZn6fntq82Nu2i/fF+7
ejf60N0evfq6+zVaOCjUd44Xd8/PFtc+f1wa3NaW6y8bK3vvWivPj9urw0b4
ApGRXu4tD18ubN6/ut0vrDWulp/vd188X/i6tnD7ik0ZLXGMEC7zC5rhabVH
jvH2coLQICzBkWV5znP4Z6P8trLrIQntn2zsVEqoUvQ2dvZK2/Q5k7n//KF8
3ry9Lm5cvN++u9jYKL7zD+9ebRQP6sXIP452P3f80sWo/Xbv5sVo+WPz+qbV
bn55e/Fyt/3yfKu9lNk5Ojw6aX3d3Xp3GOLkXiydjuqljR5Majt4B/92Tm/u
wnK5fH9RKZZutprtlZ2Vg+JW6eDspv2iWMp07j6U3jWLZ5WD4+cfLwr15nHr
Xa2+s7dQ695f7GwWvja2iq2D4nbpcNM8Xwy2iwel64vWTikTdW9PT5eLH08G
m5WtxtH+2xf7X75cDI+3RoXS17utZvH94YtacfNF8XPt9Ow82jsrvthvRx9X
PnfCs8OzzbPMwvnBbuVtf291e397ZXtla3BQWM+sDw+CFg9ieXdzwhDSxPEs
jDkapM6HZhsyEXfdkzJMQqW4Udhqdt7tvfrwuCHJtA6eB8X9laXPwerd7aC0
u7Ld+DK8WryCNd5aLN+0wvcwyB9qt+VCueE/X3nZaG6uvbsIFqLRRun84Owi
Uzy8Oi209xrHHzbv2q2zaPVu/+OwN9yLNvb6o2IEQ3J8cv7ZHZJYL6yxGHtQ
+o7RODsqVh47GseFz8X9tY8fB2snXyor+x8HlVbrIjpvvV9dvT1eWF3Z3jru
vl+87/cP7z/sjIKju3Lxy91W4+v5ba9xfrSaCbZP39c+vH219qVyU/v6sVJZ
Xrrwn6/eXJ0U3kcHTRiNq7X+u2lHI/10+B1j0b77AqPxyLE4KxaBMgbHxd3j
i+KLq+drnaUTYOgvz64vCgcvK+2N86/L+73Pw7vGSmtt5/59cXMh6B3dll+1
T7feHVQyd4u3B7fXwZdOxV9+v7dzvbsZdJfPbl+tHt0dr9yFMBZf+zv7046F
ewL+s5hV/6S1/aoXFZdPlg9edep7i5sfD5dOzl6dN883NpZPTwfv/M+Z/uKJ
f7LV2H1/9v66tnQa+WerbWhnu9Y97H3stD/jjrRT2lj2z+6jytv37cq79+16
Z63/8ey4FNwdHGe2ms1i5e6sRK0obl8V7yoBtOZ6493bL523N61muBpt1rc/
Nz/fLG7clG+2u6XTYjF8X97k5wy+ONmtbRR3DxtFP9ofrbbPz7fOo5vG+cpo
tHW/+GHx5v588eXtfXhQ3hxsvDjufwFOdzz6erpy+/mkk7lYHjTbn9u7r1of
P9YXfSjZf3dx8WJwvb/9pVw4KZaa6zAfZ1Gl+Ujm5agivmORNk4uWndAmIf3
X3rXvUq4vXdVXD4KVyqruwcfN96XendtIsyifs60G2cviwebzxf2aq9GL06b
rc8LpaPmx87zjebLleDr+7XF7ReN0tF2u/khOq8tNFeL5eLty4WbnWDxbX24
OsxUiksvBsGL0WC/8b54ErYqC8eju9WLi9PnpebhARJmePVu9bGE6VqN/EsQ
aCkoHjSJ1opnpYvay7u7YqU+DZ1lFKHhi7tmubhwWNx69/bs3cbnZvl2cH0V
nC4uLzTq/cZR6fnqYb9/u7Va8Jeu/fONYRmmYiHzcelktdxcuPFXd/qf6/s7
o4+N8tLzzy+fX4Wnm6/qB1+WrgrNV88Lm68K7YvO1tePZ/e9q84J7/tv250M
S24nUeVdvXf19q55AR9BCFi6Whq0P354/3Jj48NZqVj8DEMUlJ6Xi8VetFm8
Xilutcrlmv/lIuMfbZc+d+52C1/2SnvHJ28Pjg6+1N4jZd8cmOfTg0Vg2Ytb
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
nnQPOnKim3DXBvLN/wLOA8yVPokCAA==

-->

</rfc>

