<?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-12" 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="2024" month="December" day="04"/>

    <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.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,

  /* 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 (consrt 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_get_mode</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>
</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-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">performace</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.1 (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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
GD8bTnnlzerJavIi2uwJA95410VeA3y1LMpE0hLPEkm207D4CKjLNcoz0Ghr
xDeJCm3QVak5WpTORWQfceiuK0CKa2syKWu21W064MNlGbvIJTt0VtYLm+yC
bhdaQsQ3bP0dCKvzSkUR3fJSu0pyovp1+g92sgi0/PPqhvKSeQmMYN18WOaq
i+nKhiiUEduc08Q1jfHK9DpUtoA+QMEIJJY8cPDnVOG8IMcoe8JJkMQji6cY
5+xrs/pbSC3+qX92qpYNtEcbZ7XmX6bjZssGCPY4tNjSq8tDTptFgNVqIs/t
QHRfBpSidYXr7LnQUgsphYaP4SkmOkzS0m3NFBOWeMBIqh9u1T9xiyVKIn0y
ojiW300pLc5L4nywzfqKCKCIZkwIuouLzNqHHF+hTDqFmWT5r0xes6Tgz/s2
VQr9KWlLqNHKNkxAtyOwvJGlK915OZTcJOUmnd3fCszktOWjjVHYo9w36EeE
0yd442YHqeFwdSQzZ1r3pAEqHiy/qKMHhRh1kERi064fHAt3bvsmIhL1BUog
EEGEZ8uB14ZNqldCBGBIDNlWl86l1/A2FyBZGDdVZO5OLv1RN9q+pkUFqgMj
3raylmIIFA09IBj7yu/pO7RSVG9CNeSgCSAfHL7Z6b48evZyb2ens3vwZm+v
s/ti50331auXu69337x8sfem031xfPw6OHx+cLh3dHTw7PXhYffNy+evX3QP
um8O9473dl6+2d199Wbn2evui8OXgXMGg/sNugx5sbEf/Lgx/niNsQ0bP/3C
bkKf4sEhjlMSkOjQVgggn7uWQMAQRk3bRSoxVV+p5H8jIpQYXyE1SbJajRi5
yUBtu4LHI8OogYGOFjlKALmajb5cfH1PsAV8Df74Bf8gTRN6Nl22W2el1Mze
rvWDjNunjZtc00ElFkrGrFSZvCuLucmZDCwkj12Z2b9rqGTYmUtlUwkHvEFz
JytbkwW1bTZApMnE0CopnemlHKfht1sdf/Cos5iYt7bC5UrzFdlBWNZSEYx7
cVaLvrLDZqsisx2HnKHNNs5HigWO6ArQrle0iU0Lnk8zE22A9rLguAsq8ebV
f+3A4d+qwdkJu4ZW/dLNoeylZwg0r7BtzmkFz4xYAGjguEJb7vyEMKMmrAq9
b55ALwDHwMg9GuwTNE3quNlUP55/q1ADrkGMJkWxEOijw0T8NNulQsUZd9IY
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
hji6W7dcocfciNGND3BZMLnIfc1gCslj+1OkjBkj+ZJMwRIFMKbMDqalKSwz
pmMT28UGqaU8aRWLoq2j6LmcyAN5om0GcBI0u7WZcW2mb2HMiGk5z/pb/50C
5mzXlOQSOm8kLbet/IKBSFXIP/OEI/+Hs43M7yfZm7IxVwx2pI/GVjBTwVWu
2qVfYBNYxxjPmK78ma4IbwSczAk5oyGS9HOTOCgx+MkBBtFPTk9YST+ABLIV
fMCsmrhaPXRHA8xMStoEGglNvLXz7kyXgz/9Kat6oMsNzXcABdznqvZ0hPix
sshyD8aKd9fLLJUUdi+75V5TgdNL3RAEp49u258GVbcJ7o8sINw3rhGELJp8
xoXTQWTNTBisPNsJ/hKGBnT54Sq+rpBADIgADUyNe3f/mF8hnpVNU+5dIdkr
aQlTHL/Y8qpjeOR+9cqyqo6FwQblo1KqIjquY/vwOKXBMIIptO99cUvqpY3Z
Uf6ljYYWQydXvrjxaS/zJsi6el7c9Np3cqMYxAm5tL2UrJmOSNYwMURUojIx
RILK2v4mev8ewOeQb/msUjGo0BDRH7HXpARb8ow1njBlYIfu6aq8VDHFi7EK
zLpGvB16cWKghiQddTsg6YbKw3cUt1CTbeo7cUVJ6sIym+tTFglDz/OMxNBQ
Qmxz1ho0FsKRrOYPMjeIbKkkrh1y0MpFHE72d0soVzx2KS2jyOrqxtrq+Y+b
T04aW2s/9l+sry7srF+s7m2cvjzc3Hv75umT99HTi/Pms9P7J1v7W7/+sHbY
/eHyZPC8nSQv9pfOSi/XNy5ffvhxcfvXxtLOQf/e7vrCt7sLT578+H57Y+/w
p2f7G53n+wsX2wfvH/x4+OqHg1ebr16/Wjz96XVn1Hjz6m6r9HZze/dw8+1J
9OblSfPpaWdrc3vh7Zu9zvHTVx8al092G09fjQ83mj9ubf7UaXQ73ej19mnz
aefsuP3koPn6hw+ln94ctLvRq9O33e33P73+qRc97fwW3b4YHXcfnDfe/PCh
+ezV7ead07vAstxvvbk7f7L1dO1kaX/ztB9vtd/+9qL069btnV/vru29H+wc
dn6K3nR/6Ebdu5fN3uDbk370/NfB89fdwXftwW+/jZNh9N1Z8uLpZXJvf3E0
jJfGx7/dK529uP3t2f31J+fJ7sZF4/jZ5cve88v7H7Y/JPM/LjRfHCxuv3m9
+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
AA==

-->

</rfc>

