<?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.29 (Ruby 3.3.8) -->


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

]>


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

    <author initials="D. K." surname="Gillmor" fullname="Daniel Kahn Gillmor">
      <organization abbrev="ACLU">American Civil Liberties Union</organization>
      <address>
        <postal>
          <street>125 Broad St.</street>
          <city>New York</city>
          <region>NY</region>
          <code>10004</code>
          <country>USA</country>
        </postal>
        <email>dkg@fifthhorseman.net</email>
      </address>
    </author>

    <date year="2026" month="January" day="02"/>

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

    <abstract>


<?line 174?>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>The key and certificate files described in them (e.g., <spanx style="verb">alice.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>.</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop generate-key 'Alice Lovelace <alice@openpgp.example>' > alice.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 component keys.</t>

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

<t>Example:</t>

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

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

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

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

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

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop revoke-key < alice.key > alice-revoked.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]
    [--revoke-deprecated-keys]
    [--no-added-capabilities]
    [--with-key-password=PASSWORD...]
    [--merge-certs=CERTS...]
]]></artwork></figure>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<figure><artwork><![CDATA[
$ sop update-key < alice.key > alice-updated.key
$ mv alice-updated.key alice.key
$ sop extract-cert < alice.key > alice.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, <spanx style="verb">sop certify-userid</spanx> fails with <spanx style="verb">KEY_IS_PROTECTED</spanx>.</t>

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

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

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

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop certify-userid \
  --userid="Alice Lovelace <alice@openpgp.example>" \
  bob.key < alice.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>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.2</t>
</list></t>

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

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

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

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

<t>Example:</t>

<figure><artwork><![CDATA[
$ if sop validate-userid "Alice Lovelace <alice@openpgp.example>" \
  bob.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>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.0 (<spanx style="verb">VERIFICATIONS</spanx> output augmented in 1.1)</t>
</list></t>

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

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

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

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

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

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

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

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

<t>Example:</t>

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

<figure><artwork><![CDATA[
$ sop verify message.txt.asc alice.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>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

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

<figure><artwork><![CDATA[
$ sop decrypt --session-key-out=session.key \
  alice.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 inline-detach</spanx> will have any dash-escaping removed.</t>

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

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

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

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop inline-detach --signatures-out=Release.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>
  <t><spanx style="verb">sopv</spanx> Introduction: 1.0 (<spanx style="verb">VERIFICATIONS</spanx> output augmented in 1.1)</t>
</list></t>

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

<figure><artwork><![CDATA[
$ sop inline-sign --as=clearsigned alice.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, with a trailing newline.
When consuming such a session key, <spanx style="verb">sop</spanx> <bcp14>SHOULD</bcp14> be willing to accept either upper or lower case hexadecimal digits, and to gracefully ignore any trailing whitespace.</t>

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<texttable title="Known implementations">
      <ttcol align='left'>Project name</ttcol>
      <ttcol align='left'>cli name</ttcol>
      <ttcol align='left'>notes</ttcol>
      <c>dkg-sop</c>
      <c><spanx style="verb">dkg-sop</spanx></c>
      <c>Implemented in C++ using the LibTMCG library (<xref target="DKG-SOP"/>)</c>
      <c>gosop</c>
      <c><spanx style="verb">gosop</spanx></c>
      <c>Implemented in golang (Go) using GOpenPGP (<xref target="GOSOP"/>)</c>
      <c>gpgme-sop</c>
      <c><spanx style="verb">gpgme-sop</spanx></c>
      <c>A Rust wrapper around the gpgme C library (<xref target="GPGME-SOP"/>)</c>
      <c>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 component key must have been created before or at the signature time</t>
  <t>The certificate and signing component key must not have been expired at the signature time</t>
  <t>The certificate and signing component key must not be revoked with a "hard" revocation</t>
  <t>If the certificate or signing component key is revoked with a "soft" revocation, then the signature time must predate the revocation</t>
  <t>If the signing component key is a subkey, that subkey must be properly bound to the primary key, and cross-signed</t>
  <t>The signature (and any dependent signature, such as the cross-sig or subkey binding signatures) must be made with strong cryptographic algorithms (e.g., not <spanx style="verb">MD5</spanx> or a 1024-bit <spanx style="verb">RSA</spanx> key)</t>
  <t>The signature must be of type 0x00 ("Signature of a binary document") or 0x01 ("Signature of a canonical text document"); other signature types are inappropriate for data signatures</t>
</list></t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

</section>
</section>


  </middle>

  <back>


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

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



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

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

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



    </references>

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

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

</references>


<?line 1818?>

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

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

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

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

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

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

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

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

<t>The following subcommands:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Depends on C99 */


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

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

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

typedef enum {
  SOP_SIGN_AS_BINARY = 0,
  SOP_SIGN_AS_TEXT = 1,

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


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


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

struct sop_ctx_st;
typedef struct sop_ctx_st sop_ctx;

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

/* Logging: */

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

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

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

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



/* Information about the library: */

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

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


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

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

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


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

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


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

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

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



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

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

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

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

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

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

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

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

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



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

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


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

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

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

void
sop_op_validate_userid_free (sop_op_validate_userid *validate);

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

sop_err
sop_op_validate_userid_at (sop_op_validate_userid *validate,
                           sop_time when);

sop_err
sop_op_validate_userid_addr_spec_only (sop_op_validate_userid *validate,
                                       bool addr_spec_only);

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

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

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

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

#ifndef __SOP_H__
#define __SOP_H__

#include <sopv.h>

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

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

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

typedef enum {
  SOP_ENCRYPT_AS_BINARY = 0,
  SOP_ENCRYPT_AS_TEXT = 1,

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

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

/* PROFILE objects: */

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


#define SOP_MAX_PROFILE_COUNT 4

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

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

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



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

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



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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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




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


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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

# Simple, positive self-test for Stateless OpenPGP implementations

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

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

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

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

SOP=$1

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

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

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

shift

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


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

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

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

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

$PASSCOUNT tests passed.
$SKIPMSG

=== ERRORS ===
$1

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

DEARMORED=""

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

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

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

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

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

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

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

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

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

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

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

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

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

We all ♥ OpenPGP!
EOF

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

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

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

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

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

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

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

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

# TODO (subcommands still untested):

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

# TODO (sop features still untested):

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

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

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

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

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

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

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

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

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

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

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

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

set -e

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

SOP=$1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

It should test the following things:

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

Please confirm!
EOF

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

# Test the Stateless OpenPGP implementation Verification-only subset.

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

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

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

SOPV=$1

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

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

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

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

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

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

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

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

$PASSCOUNT tests passed.
$SKIPMSG

=== ERRORS ===
$1

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


ERRORS=""
SKIPCOUNT=0
PASSCOUNT=0

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

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

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

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

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

sopv version --extended
sopv version --sopv

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

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

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

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

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

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

show_errs "$ERRORS"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t><list style="symbols">
  <t>drop <spanx style="verb">@HARDWARE:</spanx> special designator in favor of the simple <xref target="I-D.dkg-openpgp-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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
20HiBpadZsoKG7++dCZWgjNEgvLTp/ZZUl800kWaj+XSKW02ghPblfkph7dZ
rVCgoxof1EDeZyk7fkjFNEOSRqi9UCCVlKYEwKRoQirqQyv2Q5rGINFwOr93
8rPD/Gxo2pg4/aY8q9/q3ynanKwaxwArr0UNu6z0hJ4cVvFYwgOONIejLacq
NxuIfK2+0g3Q8SKHVuA59V6U426mVjc9JcnAwAJgx59cAN734CSIMlQ9YRHq
wb3l+pZRfJkY57peqXFJqeHNziF1Zg3JFtgi2rLN1JZMf6Eb4ye2yHDdal7n
AgQ87o007+uhTw8p5zF4Ifk6oL8ILJ520G3CktnNSJKY8U8X2T4+Uutn4QwC
q25xbSWhEuySYQl895ZsYxdl5PZpeWn101NtrvD0x8Jy+BTLU6YnuvzmgMrP
+Z6q7tXyqxcT6lt+RH1o+9L1Fryl1Rdo+bKGbfWyT8em/JFS5nTKpDGHaceL
se1YfvkyvYau9/PP3tLKpEbMUZrFF1nvH7zCfaNhmuFUMyHvK511Uj1dL1GB
KGiv8VCWq+Fw/OTBkft2YQhHvnrYYdLj6Mp4RuujcHmnMa4jvU0xsgv65CpZ
X/g4imoN7yucSAg1qouur7BbRGqtpIknJNagiOKKH6pSZT+idop/+AfPfs5m
9OxZOSbbKDgWIq+xxFRF6+RqYTAVzDJyh/VFVvYgXqXNTTUjlcS2hY8Yc6g2
KkuWXNeb/c0u+1svaxfB9RFB229syy8Zbi0irut+JG3ruFnJhaC+5HK66RoT
3RDTA2oX3URoDQyNbbD0M7/CXWBGF2UbSJCRpkqhk+MXk14pVn+yvzpp+X6C
NWA1QmlXe74o9q/Mw88xta3WxkH5zhc7pbqp1vude1M9kCB96LvPt9WutMcH
MjyvO+AU9Np16iT8s4jcMj9wSZGlh6rpGEtKjaQDLHlzpaMtBDU4hs85Nm0w
NyneHHUR3ay7dYKdl2fMscH7NuNUTJflg9LNOFBaPZD+JXhw34mtBTlOujfd
8K5rV0AqHUoP31HHhNd3Or8VAphUTZhma3PKJLmc44JLurecAPxxPHK0kMSe
FNM7mYoVlsmIP5uI9mJ9gIP9YgWVKT/bchCTSLFYLhXvDrY2mrVK6SDc2SwW
9jbvi4fl6w8nW4cX5283bvy393f1d9evmpWjyuf3pZPO+1Gzt92Kop2jldvM
h83y6MPXg8Xdz7WVvePw5f5m4fl+YWPj4Ga3fHjy8d1Rub19VLjfPb5ZOzg5
fX98unV6drp4/fGsPaidn642Mhdbu/snWxdN//xDs/72ul3Z2i1cnB+2r96e
fq2NNvZrb0+HJ+X6QWXrY7vWaXf8s93r+tv27VVr47h+9v5r5uP5cavjn15f
dHZvPp597Ppv21/8pfvBVWftrnb+/mv93elSffl6FeSXV43z1YVm5W2puXK0
dR0GldbFl53M58rS3ufV0uFNb++k/dE/77zv+J3VUb3be94M/e3Pve2zTu9F
q/flyzDq+y9uo523o+jl0eKgH6wMr768zNzuLD2/fbW5cRftl+9rV+9GH7rb
o1dfd79GCweF+s7x4u752eLa549Lg9vacv1lY2XvXWvl+XF7ddgIXyAy0su9
5eHLhc37V7f7hbXG1fLz/e6L5wtf1xZuX7EpoyWOEcJlfkEzPK32yDHeXk4Q
GoQlOLIsz3kO/2yU31Z2PSSh/ZONnUoJVYrexs5eaZs+ZzL3nz+Uz5u318WN
i/fbdxcbG8V3/uHdq43iQb0Y+cfR7ueOX7oYtd/u3bwYLX9sXt+02s0vby9e
7rZfnm+1lzI7R4dHJ62vu1vvDkOc3Iul01G9tNGDSW0H7+DfzunNXVgul+8v
KsXSzVazvbKzclDcKh2c3bRfFEuZzt2H0rtm8axycPz840Wh3jxuvavVd/YW
at37i53NwtfGVrF1UNwuHW6a54vBdvGgdH3R2illou7t6ely8ePJYLOy1Tja
f/ti/8uXi+Hx1qhQ+nq31Sy+P3xRK26+KH6unZ6dR3tnxRf77ejjyudOeHZ4
tnmWWTg/2K287e+tbu9vr2yvbA0OCuuZ9eFB0OJBLO9uThhCmjiehTFHg9T5
0GxDJuKue1KGSagUNwpbzc67vVcfHjckmdbB86C4v7L0OVi9ux2Udle2G1+G
V4tXsMZbi+WbVvgeBvlD7bZcKDf85ysvG83NtXcXwUI02iidH5xdZIqHV6eF
9l7j+MPmXbt1Fq3e7X8c9oZ70cZef1SMYEiOT84/u0MS64U1FmMPSt8xGmdH
xcpjR+O48Lm4v/bx42Dt5EtlZf/joNJqXUTnrferq7fHC6sr21vH3feL9/3+
4f2HnVFwdFcufrnbanw9v+01zo9WM8H26fvah7ev1r5UbmpfP1Yqy0sX/vPV
m6uTwvvooAmjcbXWfzftaKSfDr9jLNp3X2A0HjkWZ8UiUMbguLh7fFF8cfV8
rbN0Agz95dn1ReHgZaW9cf51eb/3eXjXWGmt7dy/L24uBL2j2/Kr9unWu4NK
5m7x9uD2OvjSqfjL7/d2rnc3g+7y2e2r1aO745W7EMbia39nf9qxcE/Afxaz
6p+0tl/1ouLyyfLBq059b3Hz4+HSydmr8+b5xsby6engnf8501888U+2Grvv
z95f15ZOI/9stQ3tbNe6h72PnfZn3JF2ShvL/tl9VHn7vl15975d76z1P54d
l4K7g+PMVrNZrNydlagVxe2r4l0lgNZcb7x7+6Xz9qbVDFejzfr25+bnm8WN
m/LNdrd0WiyG78ub/JzBFye7tY3i7mGj6Ef7o9X2+fnWeXTTOF8ZjbbuFz8s
3tyfL768vQ8PypuDjRfH/S/A6Y5HX09Xbj+fdDIXy4Nm+3N791Xr48f6og8l
++8uLl4Mrve3v5QLJ8VScx3m4yyqNB/JvBxVxHcs0sbJResOCPPw/kvvulcJ
t/euistH4Upldffg48b7Uu+uTYRZ1M+ZduPsZfFg8/nCXu3V6MVps/V5oXTU
/Nh5vtF8uRJ8fb+2uP2iUTrabjc/ROe1heZqsVy8fblwsxMsvq0PV4eZSnHp
xSB4MRrsN94XT8JWZeF4dLd6cXH6vNQ8PEDCDK/erT6WMF2rkX8JAi0FxYMm
0VrxrHRRe3l3V6zUp6GzjCI0fHHXLBcXDotb796evdv43CzfDq6vgtPF5YVG
vd84Kj1fPez3b7dWC/7StX++MSzDVCxkPi6drJabCzf+6k7/c31/Z/SxUV56
/vnl86vwdPNV/eDL0lWh+ep5YfNVoX3R2fr68ey+d9U54X3/bbuTYcntJKq8
q/eu3t41L+AjCAFLV0uD9scP719ubHw4KxWLn2GIgtLzcrHYizaL1yvFrVa5
XPO/XGT8o+3S587dbuHLXmnv+OTtwdHBl9p7pOybA/N8erAILHtx69XGl7uF
nc5pvXYajA7XGp93MpXzdydfz463GufDhbfXxYO9wrve3jDcKL7f39k9bz3f
Pfr4OVgqne2dLI/et9vLp+HNwW5Yv/78Zan86kt4nDkEQs2sv19rlKdeQxmx
0MQo5/FTuaet1eD/E1W71n09mvVR8lkulXSZP7E+lt67moSfzZe8yqGse5NH
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
rp50DzpyoptwFQXyzf8CiMGqt4CGAgA=

-->

</rfc>

