<?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.14 (Ruby 3.1.2) -->


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

]>


<rfc ipr="trust200902" docName="draft-dkg-openpgp-stateless-cli-13" 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, NY</city>
          <code>10004</code>
          <country>USA</country>
        </postal>
        <email>dkg@fifthhorseman.net</email>
      </address>
    </author>

    <date year="2025" month="January" day="03"/>

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

    <abstract>


<?line 167?>

<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 172?>

<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 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>"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.sec</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.sec
sop extract-cert < alice.sec > alice.pgp

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

sop sign --as=text alice.sec < statement.txt > statement.txt.asc
sop verify statement.txt.asc alice.pgp < statement.txt

sop encrypt --sign-with=alice.sec bob.pgp < msg.eml > ciphertext.asc
sop decrypt bob.sec < 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>, of course.</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>
</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>

<t>The <spanx style="verb">version</spanx> subcommand and all of its options are part of the <spanx style="verb">sopv</spanx> subset (see <xref target="sopv"/>) starting at <spanx style="verb">sopv</spanx> version 1.0.</t>

</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>
</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 unencrypted.</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.sec
$ head -n1 < alice.sec
-----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 subkeys.</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.pgp
$
]]></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.sec > alice.pgp
$ head -n1 < alice.pgp
-----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]
    [--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>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 subkey 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.pgp
$
]]></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.pgp
$
]]></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.pgp \
  < alice.pgp > alice-updated.pgp
$ mv alice-updated.pgp alice.pgp
$
]]></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, fail 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 sign</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.pgp > alice-signed-by-bob.pgp
$
]]></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.pgp > alice-updated.pgp
$ sop update-key --merge-certs alice-updated.pgp \
  < alice.key > alice-updated.key
$ mv alice-updated.key alice.key
$ rm alice-updated.pgp
$ sop extract-cert < alice.key > alice.pgp
$
]]></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>
</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 them) 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.pgp < alice.pgp; then echo Good; fi
Good
$ if sop validate-userid --addr-spec-only "alice@openpgp.example" \
  bob.pgp < alice.pgp; 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.sec < 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>
</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.pgp < message.txt
2019-10-29T18:36:45Z EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E mode:text {"signers": ["alice.pgp"]}
$ echo $?
0
$ tr a-z A-Z < message.txt | sop verify message.txt.asc alice.pgp
$ echo $?
3
$
]]></artwork></figure>

<t>The <spanx style="verb">verify</spanx> subcommand and all of its options are part of the <spanx style="verb">sopv</spanx> subset (see <xref target="sopv"/>) starting at <spanx style="verb">sopv</spanx> version 1.0.</t>

</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]
    [--] [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 at least one of the identified certificates is not encryption-capable (e.g., revoked, expired, no encryption-capable flags on primary key and valid subkeys), <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 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 re-uses the session key of an encrypted message.)</t>

<figure><artwork><![CDATA[
$ sop decrypt --session-key-out=session.key \
  alice.sec < 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 detach-inband-signature-and-message</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 detach-inband-signature-and-message</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.pgp < InRelease >Release
$ sop verify Release.pgp 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>
</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.pgp < message.txt
Hello, world!
$ echo $?
0
$ sed s/Hello/Goodbye/ < message.txt | sop inline-verify -- alice.pgp
$ echo $?
3
$
]]></artwork></figure>

<t>The <spanx style="verb">inline-verify</spanx> subcommand and all of its options are part of the <spanx style="verb">sopv</spanx> subset (see <xref target="sopv"/>) starting at <spanx style="verb">sopv</spanx> version 1.0.</t>

</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.sec \
  < 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.bin > bob.pgp
$ head -n1 bob.pgp
-----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.
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 key (may be a subkey)</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 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>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-hardware-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 subkey must have been created before or at the signature time</t>
  <t>The certificate and signing subkey must not have been expired at the signature time</t>
  <t>The certificate and signing subkey must not be revoked with a "hard" revocation</t>
  <t>If the certificate or signing subkey is revoked with a "soft" revocation, then the signature time must predate the revocation</t>
  <t>The signing 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='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="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="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="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-hardware-secrets">
   <front>
      <title>OpenPGP Hardware-Backed Secret Keys</title>
      <author fullname="Daniel Kahn Gillmor" initials="D. K." surname="Gillmor">
         <organization>American Civil Liberties Union</organization>
      </author>
      <date day="19" month="April" year="2024"/>
      <abstract>
	 <t>   This document defines a standard wire format for indicating that the
   secret component of an OpenPGP asymmetric key is stored on a hardware
   device.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-dkg-openpgp-hardware-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>


<?line 1795?>

<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.</t>

<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 <spanx style="verb">CERTS</spanx> objects</t>
  <t>Special designator <spanx style="verb">@FD:</spanx> as possible output for <spanx style="verb">--verifications-out</spanx> argument to <spanx style="verb">sopv inline-verify</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>

<figure><sourcecode type="text/x-chdr" name="sop.h"><![CDATA[
#ifndef __SOP_H__
#define __SOP_H__

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

/* C API for Stateless OpenPGP */

/* 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;

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;


/* FIXME: timestamps */
/* time_t is 32-bit on some architectures; we also want this to be
   able to represent a "none" value as well as a "now" value without
   removing some value from the range of time_t */
typedef time_t sop_time;
#define sop_time_none ((sop_time)0)
#define sop_time_now ((sop_time)-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
 */

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.
 */
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).
 */
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. */
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) */
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. */
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 */



/* 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 int
sop_profiles_count(const sop_profiles profiles) {
  for (int 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);


/* 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. */
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);


/* 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);
}





/* CERTS objects: */
struct sop_certs_st;
typedef struct sop_certs_st sop_certs;

sop_err
sop_certs_from_bytes (sop_ctx *sop,
                      const uint8_t* data, size_t len,
                      sop_certs **out);
sop_err
sop_certs_to_bytes (const sop_certs *certs,
                    bool armor, sop_buf **out);
void
sop_certs_free (sop_certs *certs);

/* 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);



/* SIGNATURES objects: */
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);
sop_err
sop_sigs_to_bytes (const sop_sigs *sigs,
                   bool armor, sop_buf **out);
void
sop_sigs_free (sop_sigs *sigs);



/* VERIFICATIONS (output only, describes valid, verified
   signatures): */
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, int *out);
/* textual representations of verifications, in the form described
   by VERIFICATIONS in the CLI */
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,
                            int 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. */
sop_err
sop_verifications_get_mode (const sop_verifications *verifs,
                            int index, sop_sign_as *out);

/* returns SOP_INTERNAL_ERROR if index is out of bounds. */
sop_err
sop_verifications_get_signer_count (const sop_verifications *verifs,
                                    int index, int *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.
 */
sop_err
sop_verifications_get_signer (const sop_verifications *verifs,
                              int verif_index, int 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) */






/* 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);


/* verify detached signatures: */
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 */
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: */
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.
 */
sop_err
sop_inlinesigned_to_bytes (const sop_inlinesigned *inlinesigned,
                           bool armor, sop_buf **out);
void
sop_inlinesigned_free (sop_inlinesigned *inlinesigned);


/* 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-verify */
sop_err
sop_op_verify_inline_execute (sop_op_verify *verify,
                              const sop_inlinesigned *msg,
                              sop_verifications **verifications_out,
                              sop_buf **msg_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>Such a library <bcp14>MUST</bcp14> implement the following functions from the C API:</t>

<t><list style="symbols">
  <t><spanx style="verb">sop_ctx_new</spanx></t>
  <t><spanx style="verb">sop_ctx_free</spanx></t>
  <t><spanx style="verb">sop_set_log_function</spanx></t>
  <t><spanx style="verb">sop_set_log_level</spanx></t>
  <t><spanx style="verb">sop_version</spanx></t>
  <t><spanx style="verb">sop_version_backend</spanx></t>
  <t><spanx style="verb">sop_version_extended</spanx></t>
  <t><spanx style="verb">sop_buf_size</spanx></t>
  <t><spanx style="verb">sop_buf_data</spanx></t>
  <t><spanx style="verb">sop_buf_free</spanx></t>
  <t><spanx style="verb">sop_certs_from_bytes</spanx></t>
  <t><spanx style="verb">sop_certs_free</spanx></t>
  <t><spanx style="verb">sop_sigs_from_bytes</spanx></t>
  <t><spanx style="verb">sop_sigs_free</spanx></t>
  <t><spanx style="verb">sop_verifications_count</spanx></t>
  <t><spanx style="verb">sop_verifications_get_time</spanx></t>
  <t><spanx style="verb">sop_verifications_to_text</spanx></t>
  <t><spanx style="verb">sop_verifications_free</spanx></t>
  <t><spanx style="verb">sop_inlinesigned_from_bytes</spanx></t>
  <t><spanx style="verb">sop_op_verify_new</spanx></t>
  <t><spanx style="verb">sop_op_verify_not_before</spanx></t>
  <t><spanx style="verb">sop_op_verify_not_after</spanx></t>
  <t><spanx style="verb">sop_op_verify_add_signers</spanx></t>
  <t><spanx style="verb">sop_op_verify_detached_execute</spanx></t>
  <t><spanx style="verb">sop_op_verify_inline_execute</spanx></t>
  <t><spanx style="verb">sop_op_verify_free</spanx></t>
</list></t>

<t>This minimal library interface should be sufficient to implement the <spanx style="verb">sopv</spanx> subset version 1.0 (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>In addition to the above, to implement <spanx style="verb">sopv</spanx> version 1.1, the additional functions are necessary:</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>
</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

SOP=$1

if [ -z "$SOP" ]; then
    cat >&2 <<EOF
Usage: $0 [--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.
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
}

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

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

# use the first two profiles for the keys, reusing the default
# if zero or one exists
profiles=$(sop list-profiles generate-key | cut -f1 -d: && \
               echo default && echo default)
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

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
    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
    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; 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

# 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"
]]></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-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-hardware-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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
tvxzyZbQkuxivnYeOXUK+YrhngxOjl5wGrhgd2fveYgh9oOLfmcQSPmn5jvA
wBcq2bkTbG5Y4kP8R4Rh1UA3qKQmV/esvrqi2ufG1h81+YcrzMeawt0pQMJB
i0SNzaJUNGNFE1qywG1T6UgJ8hIkjKl7bImbS3S9kECrd9qKEEnKHh12NnsW
Ag/i4Sqt4+z/tvcl220ky2J7fEU1RF0BbBZISlRLokT1pThIbFEkm4Ok7lZf
oggUSLQwNQrgILV656UXfscb2wv7HB8v/Afevz95X+BPcIw51ACCat3B9uW9
p4WqyiEyMzIyIjKGLspPqGBGwsgOIq3RBee5ofRfxAOYl+h0imLjZr+vhr/B
4r3avdpdOkk13V3PZDtaWLJZ74ifcqzXgHEgsu01dre2VHvIRCy/xcVvmOWT
IP06RdQLUQ+x+cSOXBSndFPsTG4D3+OJMQA8BfytSNdPZEBVA/hQ9KWeKupE
ZjJu+vGyOCE6ixHM0nNvwLGwtscoK92FEGctJ5AK44mzqPYcgdZmEalmA2tI
KKyLCbKSOU0xzLxNRCc+V2yHr56xI2DkGuyb5linsfznBKIfBR8/rm8d7G2v
/gAcWmj9qClLIM9ZJnmqhCQmsQMPQGMhIdn/xFhy43LQkVwYGJ3ZYygyYduB
xYhN+RAth1J8Rip8TWZOSDsPRy4q6vGOQdzefXc40iCLApXkbstWOpFxbAhZ
14uyJykd0+mxNHuG2v6z3Y9pI/HjrVt765SXnxdIriqBY4jaGBB9wBwG2wsA
XzNpnsmwcYBS85zIpSYqFV+fiiRKqiDOUSDpG+31r+c6Ku5F6lpDbeYVMPkz
rDtRYi8jOOYCrgCdL0bho4qBOxRUZjyw5xgA04xcjVf6GqPCiizR7gsVwDja
ynjkJBhM1wLKAJCfmfDbCXq7SlqeZnPI9iTtRJLkTMQwCuPW8aLCUJqEKJ06
glC+Z8JJGbuEmDMZ8N2W7l2nsKpRJRx94hMDby2c3AchMvW07x+4nq4IMV8H
APHG2b1bozzxqEYysY2NZ8gSTc43Nae1e/mtPYuG2NpC7VHtgcRTYIb5PFsv
wfYsTSOT5wEzKzbfwKMlv/kP2PxibdHe/ar5CeF+ur7fBV/gn0XJmdPD3btu
D9+PL6mHRzAf9ws68RvALg4v+pmcC3OSe0N4fo3Uk5PaKzURplMOV0O9saKh
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

-->

</rfc>

