<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.14 (Ruby 3.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-14" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title>Stateless OpenPGP Command Line Interface</title>

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

    <date year="2025" month="May" day="08"/>

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

    <abstract>


<?line 167?>

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



    </abstract>

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


  </front>

  <middle>


<?line 172?>

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

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

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

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

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

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

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

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

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

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

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

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

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

<?line -18?>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: version information</t>
  <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 unencrypted.</t>

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

<t>If the certification-capable key of any Transferable Secret Key in <spanx style="verb">KEYS</spanx> is locked and cannot be unlocked by any of the supplied <spanx style="verb">PASSWORD</spanx>s, <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]
    [--] [CERTS...]
]]></artwork></figure>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<t>Example:</t>

<t>(In this example, Alice stashes and 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 detach-inband-signature-and-message</spanx> will have any dash-escaping removed.</t>

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

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

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

<t>Example:</t>

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

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

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

<t><list style="symbols">
  <t>Standard Input: <spanx style="verb">INLINESIGNED</spanx> (<xref target="inlinesigned"/>)</t>
  <t>Standard Output: <spanx style="verb">DATA</spanx> (<xref target="data"/>)</t>
  <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 key (may be a subkey)</t>
  <t>Fingerprint of primary key of signing certificate (if signed by primary key, same as the previous field)</t>
  <t>A string describing the mode of the signature, either <spanx style="verb">mode:text</spanx> or <spanx style="verb">mode:binary</spanx></t>
  <t>A JSON object or free-form message describing the verification (see <xref target="verifications-json"/>)</t>
</list></t>

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

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

<t>Example:</t>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

</section>
</section>


  </middle>

  <back>


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



<reference anchor="RFC2119">
  <front>
    <title>Key words for use in RFCs to Indicate Requirement Levels</title>
    <author fullname="S. Bradner" initials="S." surname="Bradner"/>
    <date month="March" year="1997"/>
    <abstract>
      <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="2119"/>
  <seriesInfo name="DOI" value="10.17487/RFC2119"/>
</reference>
<reference anchor="RFC8174">
  <front>
    <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
    <author fullname="B. Leiba" initials="B." surname="Leiba"/>
    <date month="May" year="2017"/>
    <abstract>
      <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
    </abstract>
  </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="8174"/>
  <seriesInfo name="DOI" value="10.17487/RFC8174"/>
</reference>
<reference anchor="RFC9580">
  <front>
    <title>OpenPGP</title>
    <author fullname="P. Wouters" initials="P." role="editor" surname="Wouters"/>
    <author fullname="D. Huigens" initials="D." surname="Huigens"/>
    <author fullname="J. Winter" initials="J." surname="Winter"/>
    <author fullname="Y. Niibe" initials="Y." surname="Niibe"/>
    <date month="July" year="2024"/>
    <abstract>
      <t>This document specifies the message formats used in OpenPGP. OpenPGP provides encryption with public key or symmetric cryptographic algorithms, digital signatures, compression, and key management.</t>
      <t>This document is maintained in order to publish all necessary information needed to develop interoperable applications based on the OpenPGP format. It is not a step-by-step cookbook for writing an application. It describes only the format and methods needed to read, check, generate, and write conforming packets crossing any network. It does not deal with storage and implementation questions. It does, however, discuss implementation issues necessary to avoid security flaws.</t>
      <t>This document obsoletes RFCs 4880 ("OpenPGP Message Format"), 5581 ("The Camellia Cipher in OpenPGP"), and 6637 ("Elliptic Curve Cryptography (ECC) in OpenPGP").</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="9580"/>
  <seriesInfo name="DOI" value="10.17487/RFC9580"/>
</reference>
<reference anchor="RFC3156">
  <front>
    <title>MIME Security with OpenPGP</title>
    <author fullname="M. Elkins" initials="M." surname="Elkins"/>
    <author fullname="D. Del Torto" initials="D." surname="Del Torto"/>
    <author fullname="R. Levien" initials="R." surname="Levien"/>
    <author fullname="T. Roessler" initials="T." surname="Roessler"/>
    <date month="August" year="2001"/>
    <abstract>
      <t>This document describes how the OpenPGP Message Format can be used to provide privacy and authentication using the Multipurpose Internet Mail Extensions (MIME) security content types described in RFC 1847. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name="RFC" value="3156"/>
  <seriesInfo name="DOI" value="10.17487/RFC3156"/>
</reference>
<reference anchor="RFC3629">
  <front>
    <title>UTF-8, a transformation format of ISO 10646</title>
    <author fullname="F. Yergeau" initials="F." surname="Yergeau"/>
    <date month="November" year="2003"/>
    <abstract>
      <t>ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world's writing systems. The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo. UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values. This memo obsoletes and replaces RFC 2279.</t>
    </abstract>
  </front>
  <seriesInfo name="STD" value="63"/>
  <seriesInfo name="RFC" value="3629"/>
  <seriesInfo name="DOI" value="10.17487/RFC3629"/>
</reference>



    </references>

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

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



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

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

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

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

<reference anchor="I-D.dkg-openpgp-hardware-secrets">
   <front>
      <title>OpenPGP Hardware-Backed Secret Keys</title>
      <author fullname="Daniel Kahn Gillmor" initials="D. K." surname="Gillmor">
         <organization>American Civil Liberties Union</organization>
      </author>
      <date day="19" month="April" year="2024"/>
      <abstract>
	 <t>   This document defines a standard wire format for indicating that the
   secret component of an OpenPGP asymmetric key is stored on a hardware
   device.

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



    </references>


<?line 1793?>

<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" "$@"
}

# 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
    done
    sop inline-sign --as=clearsigned $signer.key < msg.text \
        > msg.text.$signer.csf
done

for form in text binary; do
    sop sign --as=$form alice.key bob.key < msg.$form \
        > msg.$form.both.sig
    sop dearmor < msg.$form.both.sig > msg.$form.both.sig.bin
    sop inline-sign --as=$form alice.key bob.key < msg.$form \
        > msg.$form.both.inlinesigned
    sop dearmor < msg.$form.both.inlinesigned \
        > msg.$form.both.inlinesigned.bin
done
sop inline-sign --as=clearsigned alice.key bob.key \
    < msg.text > msg.text.both.csf

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

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

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

# Test the Stateless OpenPGP implementation Verification-only subset.

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

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

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

SOPV=$1

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

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

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

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

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

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

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

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

$PASSCOUNT tests passed.
$SKIPMSG

=== ERRORS ===
$1

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


ERRORS=""
SKIPCOUNT=0
PASSCOUNT=0

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

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

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

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

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

sopv version --extended
sopv version --sopv

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

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

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

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-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:
H4sIAAAAAAAAA+y9+VbjWJY3+r+fQk30WgndlgOImcrJgIlwZTA0hqzKyi9X
WLYFqMKWXJIM4SKzn+U+y32yb49nkGRD5NBd665bq7sqkKUznz3+9t5hGLbK
pJzGe8GgjMp4GhdFcDqP07O3Z8FBNptF6SR4n6Rx0E/LOL+KxnFrko3TaAZf
TPLoqgwnH6/DDL6YX8/DQtsIx9Mk3HneGsPf11m+3AuS9CprtZJ5vheU+aIo
d7e332zvtqI8jvDHsnWX5R+v82wx3wukudbHeAlPJ3vceRqX4SF22SoWo1lS
FEmWXiznMJB+7+Ko1YLO08mHaJql8GgZF615shf8WGbjdlBkeZnHVwX8aznD
f/zUakWL8ibL91pB2ArgP0la7AWHneC7TvA2mU5nWU6PeaaHUZrE0+C76Cb1
fs3y672gO4vzZBylwUFym0xhtUZxXiZxEVymMEJ6r4De43Iv2Nl9EeznWTSB
1e7QL+OkhMU5ie+CH2D+7eDkB36cTaDbne3t7efy9yItcRkvB116EI1GeXwL
nR+8v6QH8SxKprAnH6+/vUquyhuYWwHP0g4sW+s2ThcxTDWQBd6QLd6ARyUt
4cZfoPskvQ7e4hv4nNvbkL34NonLqw7MF3+K8vEN/HRTlvNi7+lTfBMfJbdx
R197ig+ejvLsroifShtP8ds8nmfOt9dw+KJRZ5zNnsLQnzYeJPpuCg+K0vkS
Xu/I10m28kM8dvksKmFsMH+ZdkjnCT7Jo1EyhR0IL6DtcLBISlolWJQov8YN
086w76JTxP9YZEkUQkc0R36Vr49emmrTATYdUNP0+gTGtxfsbu/uhDvb4e6L
VnBwE8FWQfd3SQmLmF7jEKoDwNnW9vVpmsHAnibpFG4ojiqEpmZXiymOTMbV
px8Dvs9pkUziPJ4E7/g93Eu9BsGvvwg6p53n4fZuuAtH9rA/OHvf/aF/8jYc
9N+edC8uz3uDpnlFk1mSdm6yopxnQAU6cGjmCawenqmncZpc4z/CRRHnxQf9
k6YOvb0KT7LbeAbX7Snck5evn3VuytnUTn3jNA0Ok2I+jZZ4sgfJdRqVizwu
NlbO+6wD93ORFuObu+TamfdZVMId/+j92Dvq9t83zSm+wkFOYmckvSu6TftA
7eiWDZ4e9497AVJXPTg9nFrQS8f5cl4C4QgWBb7Z+3SVTMs8okdwVNI0nq6Z
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
IZ3C6piDEavTRqIuE5GzGh3e9iAMXbU1zSr51zypPbPhZXJSE8yjmIoX3PP8
dVqnGJjErpOmpSI8BeMCQQRp6qdhkmIPoj5tlVQRA9yimJU5Nsg7ld1dw0M9
rZ4C/Eic8O1MNmpXq5ulK49JDc/mYTGbl6shT7bacitTdfbercnd1KjhqQeG
l9t5HKFXFrPytdUriSsPLDmMi3GEJaIrzqRXlaJSLIapgmJ1K1zwMElHcErs
4EP8S8Y1dDJSISmxnSK1lRIc7txIARJVLa3QLp3sw9vu1KX0WhYPVFHZcYGB
cmSx6gkk6AOHsJC0zxkNeQFXDKnbWGOX1C3hZYQsRmUeSMYWqgoTrUVqjARk
MrnTZC829rZxjI88HnYjSEl3lPZGcvN4Lf6x52Sdhu+Va1RuOOTEzdeouqXi
WaCF8V2+D92tQSWFLZqZpnfRklvMozu72XIy1VOpnoLG0EOfidf49nmMSqBG
ifRT+Tv4Wv5RjzJxv4jy8U1yS0mu0E8krXifejJKJQBxpVBiZJJaMKL3/FfE
JD7gAfw1SaP9075ZExge56L7fUIWGUMgaBnkUpyXlHCGq1KKwtWhC89AvFIk
k5W0Rul0VSzCHo2hzhXjRhlcz00V5hxBrjmLsJx8IF3VwVfIm1lplVzrU2HT
LYhD8zjn8mArVer/tWDPgWdsUIdsgtBsoMqfJP0yB8ioAu3dghUhkJXdM2xn
bTIwgsI71XmaIx7JRv34qMr/5UDIymL99njINQ16YZEmp6stlNJ44uuxk5Ue
/oWMoP9fDaH0+UoYrg2efBdPp1kbS1xOJ/+2JnyR6l09pbefYpqq0TJ+2hjI
uLr3h0IYHUncFqp9kK1Wkk85T5vjF39btqmfyYYjnMJ/8/dLQfUgF/4D8lCh
PmLRf1qzFRMdzky7q7S2NnYmdN0NPbNi3Ya/exuqCnIHj06D5cYaiH2KQw7I
RuxszdC6xH9Fsixnkv/LObOUlHmZrEwuK6NMrs2rFTWM41dm1mocTU215dG4
u6GDGsWkudJZxFQ/mH8qKrwcZxWpx0hhqFp6h9LCkNbqYDVV3K/uzEkox8VV
iPXQCgPlVIeTVYxEiqrObA2Xrp8fdhoB299/3/twesbs/4/MTuSN5F8FGPM/
kKTIm/f/n6vo98tV9ODCNqUs8j7638tc5IoG1YvsOLeso6cxn5HwPiNAGZzy
C/tF9Z2GrEa9wzpqGWvB7sE17e6+eEkP6L+4TK6nh3Y+J1cSFyOgqIVaGtGH
cojCjwmlAnQT5OsWkHqnbe8FRCfVrjaJzZ/4mpM1D9OScyZ8jNsYlynlTMaw
MOwaa9qIL4ga2MMcgxj5EOwzawRy1B0c9PtW4qP3moQtkwDVBGC7yT3bFgGn
IWYu2pIhcJ4k1iisGV5meqG7QGMM7ZJgmYA20y6bwE+c1nJLhM+Iolg4wgut
1k2WqdGRUiNzjdA5dFnGWETAYE3xDd+cVtjAXLIOu91lC6x0yo5C9YbblL9o
VcT33FIUnuhmKqDHtYDyoYUneIxUAdV+HJL4BYm+alANqkOVqcBFoHKsGAr5
AkQ3rq0RfhcvJV2yNzoHKDzHoKiJpI6WEhy0uJu8XzTLd7AtKFPaS3V23v++
e9FD0T7Yf3968N2Qiphi9y+h+7PFCOjG53Yv+v2j+r/cf98/aOp+x3aPxL1n
PP0DQQHgoOgQw8vPcKk0onDN+58zCQcS/piZCLWzE3gOYzoFenwG/MpKbo8f
Qs2o96tGsYsrs7Zz8e+IvhH5GYK5T7ogjcNBSt1vuDfWhkUGr6qPrCDPUuO0
G7pfP2VrxNmS0SSO5wYvtowsc33B1RGtHtBv3QffpeSvksl5yqnnWVSQctVF
/I8FlkwnkUUqpqOEJZKKUJsVPqPWIMFP3Tcjye/mkO7YFCOwwceioplKbW45
awK0TeIZe6+RGONXoamhNSEhEj1WTgALJz/1g0PhWgP/JW4Xc71kKc695BbR
AOzEd/mLBk05/BYJbf+vx709zkzMdcGTin8wCg4GRyuM5N+ApJDHWnCcye/7
WIrbAFPJFuSKDkOexW2STbXuN4wgSmZiONM50YSQKXqpdAvaD9LIQ+RWE8cZ
S7qdyKlpjKApkI2hJW+WoZEUVEQwe1iZl47URGKjdfomLhKStU/PBrqemyR4
ulIpaiPsHmhKwrRp6hy6/gIiNedRQiBpU5OHTJorBFVmuV+aYLmvA6+ujA2M
cx9XpMEq46jGxq2BHIlA5d4NB01kTedRYQItkcOTVGJLa0m4gQNm5+OXffQC
ZzMMg2Z9Z7rAJPXDaFFmlDAhucb/4XiEIZroRShTH6fW4aNI6nhiDe5oOpY6
YFZcoimICnTD9IhMRGRj5cGouCbmMLVocUyQZEGWWSKAT0fKo9BSCHTsOY8k
YlesowFtHwnuuRvGQ6f6zmCnKIMywWEyjHygKFEt+bRIx1ykg8svcXxjRUim
c0/hs0Sl3NDGf0kxGQlaRVQWEMPnsgXZwsdyB1mPVfwhCNA5QBr6/T1vVTQN
aShmpOxDsGzENKmMpBaOW+MlDazmD2cpv4qfSN4d45ARJujn4fnVnObxHEZM
gGSKEYYAQ5xSsL4Oite7whC8vfiNDIEmgLr6UAjJH88R5GzVkyZX8iwDzTQ0
nu83XEW6VpiiH5T+QebeQTEdMm1nnc3GcVIoAH/cbGMBAoSYBAylhgZ/aSGk
tD84DV+/3N4J7KmnoMQS5iT6ILph/5mlsQmAqiTTxXS7tXS6DZl57VKJSogf
4v+6+UB393Z29raf/+f29t72tv/r84vdZ3vPX+/tvvmb+WFnmz7a2dl+Dg8t
ONOpl2fSdgmH4RzDuCxect8ESU1EfoeehpUKRk+TJVWyBm9g6QBcnGkyS7As
K9zpq2n8icJfK9gmgYwNXZDThL3XsOd0X1maX6TRbJRcL7IF8fdZ4SF/EO+E
gbbSGPt3I2fHJN0LWRirmanxcpIxTw15XOsKZLgDKaVrDgOaeqZozaxm7pJs
I/Aomy50ZuTUikFDAWZorfxaIWn4N8yzdnWVfPIPCYwZTxWfSymadv/E1GhT
KxpJJCA25kgqViYh67T2l05hrHYwy4rSqXeZOwJMPoNdTor5FPTEE2RxX8aY
IaIjJb6+FRNHBxbh62G7Vv8gjVW0gqHvLxknl1LoM+j2y3ZD9hTc9DwmjF3k
1CW7EhQmVU4T1IY/Q5IsJvGYvInYKXlIeBMKW/6ukiKmOX2LDICYrlOGgW61
IRzU9PgmwgJ9KM4QHzHOHQWQUP1zOOVAMJJxp3WKKe4WOSIIchB9CgGSj8Uj
TDXTkvEC4TRajMoIBHC6KPFLQ1odpMTGDkYRLgRYdmv+ERSZ1XY8RYPL/YPT
4+PuCZ4ky0r90zQkJm7OkFcWCxcH0fd6qk0xV1u8aZpo7NP9vfOchAsYgiQW
gv4lfcwvQsP5xrotUTIEJgWRlxfJSOTssWBIVFGRze1ATdoiokCawoh+Jf5N
J8qbLlacBuLlxFnSWlJNHexS2uB7YzOugNAbs9+IjYQNIE6SsAxySsUTIGC8
pzgoILPuGCWJanKbMIYHEYt3Gf+EQytYFu33Lo7sQ+MsJvXBPO7U5p82vBXQ
JKyt89uhPfHB5van59tbouYo3OjwZCABzdTKqm4qY6wUZkv9nho2yxms7EqB
eXAkKRZagPKMaoJrhij4LTcQcx6fQQ4gwV0JteULrc/wkFCvOpyRW1YOM/H4
HWg9RnVQ3sR3eD7H04zSWME/TRYIzWcBpAII8xhDFIpxnozWTmLl0lQWmBOe
YjkBZzvlnA/zq7FJdEcbYMfAd+DBQVNmKFRJJuh/7ujBRtt99JuHN8mjqzL8
/UbYJy4EgsohNmzT/2Hc9sQf7VD05OGKcRd4MJbcuAls9g/QF4VRtkUHUPAk
K3kgUJUZO3+oy9LRznUsZhiMrWfngf5oqSxdUfxT6WMxdFDKDqTR7YOCj68X
uUSj1ks5SVvYLlHulatVYLoREGZBh0dNWrCc6P3VZAVeOrMhL9vKVdM0cARc
B1UUs0zFCNSbA01OuKyqdNcOnM6QSXsdBVb9mVS9cet2gszHugOrZ0bwHG9i
f+LNoNpjBSVFQ0+vv1QkXUZjUpkjkB+LWKpUsWzrvixxrcRgUGs3NiF2bNmP
G45OJZCFkudyy7MYMw8nxUwjlVOp9m1jdklYx8jZaCm5vmrEMcOS3iSszTJ2
qs8If8Fh1gZnockxzOcwReSstzGpUYqChkYLOnhIA9zNaRyfK+3iXNKYi4eT
RB5/qp1szmjcGE6hfns0LlC8lugQEVmjWNt8KkGufQVNkNpJYD0PBPEIRVS/
QPoIH0luwJEQEq34xanQ6Cg66dBM3IJX7ZeENnUw0s8ox2r+9mr/yI88Sxmd
4gnccU6zZLyc9RhfC7uQkqpirrBEw8kyyCeUMthxdCMHi9DaGqZJESGrElEq
8rd/cnapuTErnVuDmdSM8yrGuVw0hnuzqiPXf4LisejthxLXkuVsQ65tvij4
4cS+yNYCg60xgih8bssMMjq9jLDSOI3gy8XX3375dPG1Hnm3DrM5CKxiET0T
AkyGbRksARtIT/Ec5pi3ETVK7JGFtUKluU7rL7FZIRImiYwwucKvsDLk8Nve
yfd7ghL79uhwb7hFoTTrRSaYe5zcmthJM0i7UL7sRAUmb+D/MeM1IzQiyX8r
EzBElcNJ+dauSFo6OOsd9LvvP5yd9476fx1aRHR9u0y6wzW46OgqNqtr0yrU
p1SI8ZpWrOEQUQe99DbJs5TOxPeIhAIxxYumoiuvyRXNObLQNPFO8h1AMupa
mlhppwF8+vRp2G4R3HrM1SyJTcRO/7fSfzD8d3xbQ5YRqVHitYXXp1lGOYRq
IVudFnVj0g2JvzidLvfUNCo7pycocQqFkmFbAmTkhujdXJX8t76pF6Jb3ZK6
iFxHIJH4DO04dEZGsQsBkzSnJi8ez6HheNIoKffONL5FA48YoOjWkmuo1M4V
ur7T2dYTAPdk1QE4QiJ4SLduXqLj4vP3Xjz2xkUvK7niMMBY0hRBbWRDGdK/
Sd/FxLozAmKW8XWcy2Ehf1FRZOOEKJCSeEvHNeRPJsAtwsRPU6zLUHIID6vk
Jqms/4nEkPzmvTs6/KytQxLGS/WobZTAsvsnaHJCun6aknhJJKIhAWnhJsDb
2a6CmUEG+RgFG4RZAz5Pk2KYCwJUNjqtY4ZjqNNE1mOljwYBBt0pxmtd37Ax
l3gpGaey/OMVUXonsbCks6JEMn49NbprJtWeny+bzFqbMG6JHtyAedjUkm71
GTfUCM3FPhiIOC4ldOaQlzzWrSSsohiaQchPSOMXRu+3YaAdDQnNlHpU2YLD
2UlKQrWSoXlVyfdjHM/FGYCAU6trq9QGHWEGax6widmJnPtZqqQ+iaOpsRLC
GtJrmkS40KGwRgt7vZCoee0Z9B8EbZNKMB5TMD+X0PgEiu2qjG58vWkIszji
HGv0Qewgs0ysFxxvCuq4f4J5J1ccbu+sMiANz2r1oNdw8r/iJA+actQhw8Lg
XKk9U8ngXcWQJKWTHVB083E211zplE5mYqv/NHe4oitsgLMMrASU1/MNDOn6
2cPIJ78Jpf0OVDogP5I9OnLy7DjD3JQiDJzeG+fZPNgtou5qjNShmELQFK3s
YCJZ66GuFQf2yFnieYFh/AY65BVX8skQpUO15Meuw3oqhAs1N0kgfx3xQdJv
gABI/20uXwaPWE+4eIYwzxfSlXii3MwAL1hHTabLMOVkYNegBMyi3CjyYt7T
O3esNdlBlwedj0v9eNftWfW6oTfPug7aHFPL48N5afATj3aP9BMDjdA4J7IP
FVrGLfJQBmeY1rHw07tWmBsnzml4rzLYdss1GFMSDUykW2m7PkMU9fhNdAZo
YiMygqv74Q4tSegKIp/pBtCgEafogL7Qc73BdIj0QKrF0yJH+gzddoUKOgqo
UE2D2E1DW61WUwdJ4a8cjeQk2PxnnGdKXDGgmuvgOEFLBhvprA586n738Nu4
EOqqdyZTfe2k3lKwWatfUnIWjzhvGG6h320ZXAQpckhWyyybogNwLAtLJIPL
dEl0zDdBcJhh3Kj6B0XfwzX/pvVreAfcVxf2YCIoJaxQFPKmZChIlkqqMpE6
SfMQsWETtJI8SzvZVSCGezmqgHTPTRZVyEEtWjBmzVnVK6UNZHpdeeVhKBeK
OqqjgaQamY/AeXAZaXo2CcjjItCsdcUbsB+JxpfXXwe5Zjpdg20yWiaauPFG
szIhxIn1V9J9aD/wruVSnKOGM654phowLJUW6ojtYPP0bLDVeN28y3a44rJR
nrp/YARVupiNWKCsj7Px6lloTtHi1Oku1CYxKVSA4uWSb2xz7V5tEVtQDdGC
EzHSAgV3gZpcsOcFwVG2cgeuPXD2KTpXEJ8hnnfsCj7pUaWjWi4kv9ak1yT5
cOwHFzZcc0V4JsGK+qWbm1iIs0l5Q+9vSjkyicx4KDRp6MhZinfiyB/OnMNt
UmYJp8neyWFDVNJQsK1oONpi/zBmt0RxSCmEbycrCOygCBOi8Awm4YojTK8C
n14x8KbJ6CYrQzZ7dPZjgQu2lkvAm9iscG7XN6ij30VycAqxedoq8PdPDKlf
oRjUTnEnCH4d4bbp7bFbk69ekQh6AniWJjnR23Rx9pa8HWM0awtQwYfgwHke
YpWok8vjvXe9v2IC/VZLbCDyfKjRZ2oJYTSTY/0w7kgzc1O9ChShoGsq+bgS
zJta8nsynsogtM8bEFul31YFPCRUUrgNLIdFhAXd3iDcffHSTYkpgLo3e0cH
3ef7ve7Ry9evjp6/3n7x5qB7cLDz/GgfAWC7Lw4OX7x69mZ3v7v/avvZq4NX
269eP3vxBp7vH705erV/cNhaZdOtpET0yiOIN4LcS4yNU4i0vUlpfMfQur+I
OVJyTat12Lan6oqJqybhXX0iXgJHRqXB0WSgGnrb3EUFFn6dINkmCESGzGYc
c05SOL14mkleqefS5oN53D+AUwKHcob06FoPJNuPQpL7yePiJmGOK5n0YAQg
87PZjjQ70EEq0afq5xIstGImSd2nT0R618S10BIcw6fH/eOehisq/gUrIiB9
4AF/NXT8DVpAZMjqFdC8pxrmLbZhnkxUrOLpL+REP9t58ZLDb7U8pPVgxRYe
NU1AqBrOr+dhcRO92NkVeFgisMMiKRdCBTeNxufIlyyAOEnyaSGLrUAzoo/i
Gj7LZHAjhIbBEaJMDvL9bDTllTerJ6vJi2izKgx5413feQ0J1rLwE0k3PEsk
AU7D4iPSLtfoz0CjsBH4JLq1gV2l5mhRihURisTTu66wKK6tyZCsaVTbdMBH
yzJ2IU126KzFFzYJBt0uNJGI09g6QhBv55WAIoLm5WyVhEH16/Rv7H0RyPnn
1QPlJfOSCsG6+XjNVRfTFRpRWiN+OqeJa3rilSlvqBwBfYASE4gyeeDg0qly
eUEeU3aRk4SJRxZPMc7ZV3P1t5Ba/PPg9ERNHmioNl5szatMx82WAxBMcmhB
p5cXB5zKipCs1Qyd7UCUYkaaotmF6+e5mFOLNYWGj+ApZjBM0tJtzRQJljjB
SKoabtU/cYsgSoJ8sq44JuFNKRnOS+J80GZFRiRThDkmhOnFRWa1RI6vUCad
wkyy91cmr9lT8Oc9m0KF/pR0JtRoZRuuQOkjEL0RsivdeXmN3OTjJk/d3wvM
rrTlw5BRCqScOOhghNMnQORmz6nhcHWIM2dQ98QEKgosv6gHCKUb9ZxEYuyu
HxyLg+74tiPSAQRjINhBxG3LgdeGTQ5XggpgqAwZXZfOpdewNxc5WRj/VWTu
Ti79UTfavuY7BaoDI25bIUzBBQqTHhK+feX39B2aL6o3oRqK0IScDw7ebPde
Hj57ubu93d3Zf7O72915sf2m9+rVy53XO29evth90+29ODp6HRw83z/YPTzc
f/b64KD35uXz1y96+703B7tHu9sv3+zsvHqz/ex178XBy8A5g8H9Bl2GvNjY
C37cmHy8xpiHjZ9+Yf+hT/HgEMcpCUh0aCsEkM9dS7BhiK+m7SJdmaqqVHKy
ERFKjBORmiQhrkaM3Cyftl0B6pHF1OBDx4scJYBc7UlfLr6+JzwDvgZ//IJ/
kAoKPZsuO63TUmpht2v9IOP2aeMm12pQiYWyLCtVJrfLYm6SIQMLyWNXmPbv
GmofduZSsVTCBG/QDspa2NWC2jYbINJkYmiVlMT0conT8Dutrj94VGZMLFxH
cXSl+YoMJCxrqQjGvTirRV/ZYbO5kdmOQ87QmBvnYwUJR3QFaNcrasamRdWn
mQlDQENacNQDXXnz8j+34fBv1XDuBGpDc3/pJkf20jYEmjDYNue0gmdGTAM0
cFyhLXd+QphRRVZN37dboHuAg2PkHg33CLMm9dlsCiDP8VWoZddASZOiWAgm
0mEifv7sUjHkDEhpjBmSYHjYEkpIY8rUE6ZySug4NpA2OI4pE5I0XnHNPjhS
Tu3jf6R0ULChjNahARpZu7osusie8/dxa8VERtpr7DokiCTePdikI8No/ZBo
Nvis5rk4A7LjUhCJxIv+E11t6FcF4Sq6w4PcyFhFSqcX4RvvmsLgUEjYA5Fg
w97zDe8YOgA8Q5LalU5CE+6mdxWu3m2WIB4dFFhqlWmlEBXr3xE4RJnNw2l8
G0/9K6DoRN0iW+gM7wBHtKg9x0OiijfRatuR17Cb1SQKBqdVAxWIiymXFyZX
nO4s684TEyXX5Si5CDiQMUC2HcpNq2Fz/ZhkE6KXoFkQ5TPHpsjKJfWnZVzc
n9WmSPo+UE928ZkLr3lobTIkKwQ2VngdmlJgQwtbk6x6zsZjniodRgZUrLSp
hRjnq6op+XtFQBQFbVWSPRsG874/uLChMIS2foxeQ15uSS5Ai4PGZq0coOKP
1XwMLNjqN25rzNMcALwa76bLijUdjjTyj+1Pz3YQ1yJRGPD37vaWYm1HeRJf
VfOgKgbIZcyKwbCofn8s7nCV1ZQct7YD/IlPUltd9DZh+3MbniOfMVViPlNI
OCKH1bhAELhM4xohEYQ/OZFv8KppVfJC7UuCH6FgNN6XTqsBsI8sbRS7OFmp
YmJR/pzIRNNC+L8SqUjd0ASOd0IcuDHzNIUIoFZvHlmbNr8q5FqWqTagVtdJ
kqRrunIinwOWr6XKk5GYXojxbJLRKLvaEjO2REd5w4HvTeI6gcvrsgj5NxGV
8GiGhkfNmbDyiBrgqIaoraugp1KCjbtqPtnELy1A/0lwBAQDGcIx8EEEFV/x
3yGqC4VBHDg162RVKJPjLI1n6DLhY5gieghLeFDKiY64jjSijnLxFpZSSZOY
u/z0u+GWyYRsEiG7APAeB3E7DRJQk1pzIJuc0I8c186I206W5czxJ2g1HfVv
eNh06fE7KXHvTF8yWYP8d78Hql85jb/a6Amyw7628Uvre7Ln/xwcyyrhP+MI
u2yFYbj3M3pu6L8e/58WrNfPnL/752DApqRWsIPPLk8Io3rUBxJ/1O2/p/TS
P6PUkqmaAzzVKVksG5+NKQh80gqeYTN+euqfgxM1C1QKpomLbdPNGb/V2nkm
QzHA2e7gh+Pj3sV5/+AD+j1oSIVxY0TqwsChMcAy1kbV3AetvsJWUcjTPIi9
Ey4XBs8PHFGWMP1prSiuhFsDsdA4nNvsI/5jkTpzW5Dh5WoaXRdb9SG8wSG4
ycBxN0Em5dwakpZS0cStXVqHVcXs4Ld+yqEiZcW2g+DnnDP7FzIINXJutXZp
EJWKafDoslpwrfblMzoiav39gN+/uzzunnw473UPu/vvZasdISP3jk0OUoGf
HdNfIEn/oWAfKiQHvb6qngZOzspjtvvNnL71nAZpMJO0SpxS2OYI3cQkpRaV
Jh41hlupzbrd8IZoCPaVuBxvtV7QNvmSkSyECHsE4GJsIz7Q71svaCv86h/w
ROJ0GoqHtl7uuCeIg0poiuYDPyyl9ZJWr4bXwwvkA8waM9WaCtJtYy4fKkJR
0r8mpVO8eF0F5U3O0ZNNJ/4PWxpl1Xr5prrTNsi7uts2uLr1aqf2mY+zZwJm
sOjWrcHWhzr6ejPxQ1uG38Ioqa4op+FYE/JhgwZar+hcdI/3+28vTy8Hdre6
diyaQOfXjEilVIO6J8iOCbGyH1POWy1QIWktX73Rc+EmhYVn6BPGudnU+7+Z
AHJuWeNvMR4YngmXiuF6oFut1w7Nq+Rixpsh8XhUT8DqS5rlkioDkWg2lUJb
JKkQDWq9rp0uUVyw4QuJuopd0Y3svTWO4pGntj+lLZM3RSU196TagyM2ciP5
cct+5OtW680r4aXvuueHf+me9z7gfh2dXvJ10NiRmq1AowwKt/zcFcn8aGAI
RxFhbi19E7wV20koXJGNR2w30u/gSN1igUtRDCvNhdwcJh9p7WzTlfSHbaWJ
lQPH8tUTW7R69YBNpo6Kt9oMlXJTiKHHpmti6+iMIvqKLPWTKo6iSXDWP+Eo
N+VPj5gqHdiz8/5x9/wHminwHp1lxakUVeDCaITNEEgYfQxI8qMLBW1aUYUT
iACv/XDcvTh4Z5bPN5dJkgdDACRtBrRUveb4Xf/oB/emW4PZ7yLucHPLkLO7
DLc4EqJ5w6/UNUu7gmG6NCC0js8wEEeNlw6MhqR1TrJCcnKzyCrxR0aQZ9A0
y/GU6IBsEWSLF3UNNKBbVmZYWu/7UCfRg43xtoqEwkPHpiZxUJM7Ry3jlAHA
k/W5k0orIO6f5RntKBH0n4PxNNF/wrDjoiXSvv5/a/LxOsRVh12Wf5I8YHR+
ckEd/Od/Oo7T98no4vjgLUx8ROatzfv7w+/ehoPTMzzQ15k0R/9oaOw6m0bo
u3+bbUmjb9UgDC29PdV25tezWIdm/mD2d45Vn+/gzqJFJ8pJByDsKL4WHLgj
e3v29rinY4M+oiSdYuQLGvt+JniGPAlhqRpG++foNpJhOl9Dw/BXt3/yvjcY
hAfv+9j6+cmZjjdP5w+PFkeZzv3hYhsy2Fzbal5GatXxZucwlSQG6SonVzM0
Je0MgC1lSaQzLv7xqOYK/ioE4pdCy067g//idmFY+mvn7wU17T1ZsZgDsixI
V7Lx+D22fHoWnp71TuDJnwfSxfV8KU3DvxqaPFvCLUztDi2lobdnP5Aj+knQ
nbK5POa8Fxi/VCi0Dq+VENmECjVfUfKkyPNs2LgnQZksFC7Bxi9CUHPahGxR
0hcRm6E5aiiZJBllP3ICqJCTHATKTpiP3AHXnBLdIwmCkMEEJILrsuAK6wdr
W5UcPCLxR5TjQS08dwkX5XUQRU19FJQPrOINx7OxB2zs/HJwwacTHuJe4kPc
tD93v+/SQ94NfHz2w8W70xN5W4yN2mHTqC2GCqSI+dSG9OjFkXQSQB8XJU+c
3lZpyu4Z+/kIhF+V5iwt7bQaaiRTFwSw9IrHm7VRKxrI0dcSae8jl1ftdCx2
+gm6NrL5TF239BaJF2wLJPbx1q0Y0XeMr2oGoxGC2E4pX4rFzM0x4RlrZ4hz
ZUwcJX7n9CdsdEdIayXeBjlPFFwA39GeKuGBDKhgezutL3XJ4hEbrjKnVREt
qFFK6RcgftlmmcbNyQqOz0qugmW2MEOVLBRkStBsosZvV6lUYBNTijlSElTi
VmMQoPi0yc1CEDnGd8NOOZuEgnX6hZ+AmKPn+MPYVkEjxC7+xgasgQH1V1ZT
8c/ss80RjalYfxxQde0dVz92joFSbugabh4Cy9LCgTbfScgfCJmFpHRkT/jG
NFrG+YaKn07wlkQSSYIzwqCM+P5wthmgcPE40iwgspbkZ9DATEXlYTXfIqOt
cxKROEFeFpdApgFKKW5SAo4XQDwx05Wa3iQ1KhXqoYGlVA36CqMTSGu4XUxT
56LYiFQEYPDhtNfZ3PiIexbyAfQdnZuY+cbLlDfJnCGh8ZvjURA5kFZ3ykso
U08IY+v9ipJK/nuq7+Bo+RbrHn+yCyVqVEK+DzySbl52lV9ZJSGGYT/kwAZs
mo3gWEcvKW1dCZpikVG2C80hS8BjH1yOORdnmF4mrjE5g9GAvRdIIhrF8OQM
rDn2FMViipBn+XTAwARiAAKzYII9pVhFChxEOiYABhh3FrD6JWHrFMcuuIBK
wJ4Y4tnqq9hgrc8oOS8/zS3igR2mJo2uo6Li3pgedSjRjaR/kHSkSDNlAH2O
pZeMn+LOlRImMF4/7Oj+ySr8f6tVy85MtleK8+a2gRdL836jmDvEJsTtrLvR
5kJbpIvw2gDPOVzZrLCB08qjcQBfUMbFCcLn2K1EhgBymyBLjoCT9GiBVWiU
1TW4Y6LfpSaSpK/J4jT5OwqboAWCiowEC6PJ4lnB3hyMBU8nkXBI0rvQppGq
K1H4D+p6tn2T7KySb5oUZCpspqG9ZJAAvhiMEoP0ZAcgebSlBt1ey8K+n1eC
uz24O2Ztg4ZeOVWQs9QIXW7DlNuqVgq579TZdMbedj63+Qahjy8XX4eMI5P6
UmYuDmOlgN6Jur6U70vVPpOn2j9R1aNokgk46Uj1Y5Ncx7HZurneEf/ErgO/
PNvL6kri7WZEoocF2eJQw9SgL7xCE++BatPPgipzAp6a3juOppIAm8m9bI37
qqmMJM2i1u+gNhkfZ9zF/OVFlEzl9fNoknwKXz4PFMdDAigLLcYT/+qlA/5C
JLM4FXxcGbavzRlYEPbP65HIRzyEg5t4/BF4MsctJgXnSx/F5V0c1ydJ62Eg
/t4kjr0C7xVKI5YmLZ0O+8/FffJsBLeYCzytiVeROBNnOZtWUgoGUcK56cJE
77KzJenEnXYlbb2mq880zF2quyxSHTiRG7z/eXKbiGKR4rUFHuHIB5JuTlHQ
gqWmPITUOVux6N3LNPn0RREMoREQwksSRDCZsFgS3Y4LQRSWTZ1m5GrBq20L
aXUsVgqN0ARIQWavhQUeinozV3QpbmuSTohKF0Z0t2MhY6hGfTZteNFEPWrs
SnMwoXXvGkgY2UYIhcDElmXIFayrcmzsDNxkIpInjXmRlJTT8sCCnKrFH1cy
HPu9cGL2VAx6SQNR1gISqD8o7aCDZnIw06mSIA+Y9oh0J3OqJW4hMjSej7YI
MZqizkREEkW15RnosAfBiuNuyjV4Oe75GjiFG7Yqs6bAE2eBuVM/Cx0mC8Qr
o9EXGnpTKeY6kJrqftlDA7tp/qxieKCPJMkEy8BJmdgMjusDru+f2IKeqqfO
Jf9oFHCF9dgtFS5RFci0iDCrO6NWN5Wlb8muCI1dwZukibMKWUlo0xBLLwyv
ujkNJei5SoRINKJesTKgo1vRgcCuH6iKejA4AsL0TvO10ReDI0cjM8UQUDsS
Si3xCBxYosr2nFyGJuOuMaET+kRyR1GVdo5Gp4ShsOFI6hy+LMOXQAWJ69Ug
E7lumyYegvhn2+wP/15sydcmAJzUYI3VoJTQucf89EVlefZEbDrDd+DI0hFf
cu3OfFXpiVUKDGZJTeSj+y7l1+EQDUsa7AtelVBRTszKyV2Sz9mKM4oroQDs
veUf4e0ZrAaiNhUiW1GWCowcYKLs1it28BVOsS5PZc5ocqT5TVEtTbh2jaBw
KTOqlsFo+M4HlrQlBaQ9UmaTSB9OyemGMT3BnSlG5uQxdliAV2IdeOGCFV9K
k04Q0EqaCxkUMhJrs9MwMZECMEf/lGBIWuhhqcnrCw7nFKxrakayQO0lKoHo
fCTIo2Yzl9qmmgDgxx56ln6iZNV+bKafKnJVEW67e+6imVhwvNyciGhLksMg
Fayc+lq1EnafO8VT+bOhiu3eU5NsjW3plLhVwyixyyKWa2YXPKf4CLcDQWiJ
NRJkoJlFLbnau1zZ1ETMyXnFU0LMf0tSH1FSfwn8EsZVTV3mLyRznXMEElHG
EBCgFAWAEC4+RJTfi3PehdQdCHqhA+PEdCogASzIPIiLQanU6lUUsHJyoHm5
Cs6HzxoB+vZu2X6iBNqUhjDS35iUKy8cAUdHUHSS1sVKpNEYcvBFlFUIqnVf
FyKKuKmi2ZFdrKoDYQ1XIsfroMnW6wVwyNCsKOPC0ZOS8O+xHVUieR7UuDTJ
yISTSeEAbJ2AMTecVc+ZekThNilsJhllKa+OXife3gsJNhKFnKHh908Iid5q
YcZRDCecT8n5YIrjatg5TU6OpX57/28Y9/1y9w2IOhRRQLqZJsjoNIrmRSVX
R8F8QxDqmjPAhjJYPV8b71gLUcWbLNmzxdMjRkUaqzXg3uo8ld7e31vNW+eX
uMyceLi6/kO/EgO6gRj0cCVIA14pVD6tfI/yHI5yT5hpq3XoSk1WjEmdSRcY
SIBJTLhqSYzpXMw5EYCo0N/7+wP+IBxAg4RV+OWXdhAL4kkTBtCp4RfVWmPq
sSH9N0meiUtjdk68aB4ShBKC0gjGqGZ3WueS30w33WwiRlsIXnGRYv7oggYS
jXPgXDQU3cR4nEmJIxJ1UrnSSzbFUrpD1Q+nnOTQqwunAaXaG5JdthFQqk82
lVh7ggRXaHQ53Zt3hPM+V5z3/ZOVseitlv+lNdtWgvL9Ftoibi8rTj3gcNCU
pCGkutISoIp1BqmF24TYfFv+LN28i1LgxkkSaLpwK/8ZPS7PymyccUVPE/tf
kM2MVVK4qbDrmiHSSaBoFDx0UgjadJSwskP7AKRnPsetUVFTi+9QGTbsjD1M
s+gTZuDAqZOhxGjygfZgkhXUMwp4EDEn6aEpB6OeyloqSGppS9195DGS20C2
YMqQpduKllEZvFR6uY01HYnMst3CMdXSKtiRMjRv0/ztVoNvO9XwKsA9vKTS
mE0GIjGNfwoePV9pguaLHnirtkyBBJLU6DowuByufG7YEwZwKyZ5KMmL39qM
I8deTcPKBbJ35P6JzVIS+nfiFzGlOGlMDJO0plQzsvbjTkWccpCOVR90Zi5c
c8ZQf875Ur9ZnWrexLoY8MCo0/jO9qzmBhLNfKuwMkDhX1rrRTdBmyAWpMxJ
CB1qXnkya0qs4dRLenDBqtwZ5RtOiIl2Gc4vyMkCvPT5xiVTpxRC5FxKpVSB
lpq1JCUAXEvBL77ldevPQu+cPwkqCQdaI60THACgTSb/l7Ms5jc0ZVOKCtoD
a2t2kIvDwVn3oMeRzrvbW8O20IAiGP6td34a/KV/ePEOhJiT8M+n/ZPeOb65
u719sMVjvOjuS5T0m62hs3nekRT/bIo2VGJYJ+wRP0JrxwFCdi5P+genh73w
5PT8uPu+/zeKUSAEz/dUc9g6IRGSgcsWyrJRKTU0HxlDYoH1P0i2EjMfiofr
wg46mvXpoeWvAkYMf3NEPSyMOMMUTXJBYZOTNJktZsGGJT5lHqfX5c1GuyU5
gch4dmtK6RIsqNKb8QibeFgTzI44GQSBmg5Yt3tgzk/IAKehsWd19L6hfaAM
6XuejGBCoSxrsLqsQ1bVTCzOTKmFsSLJbm5+qGbebRu0QyIB2zT3wsbSktTs
gsbRwkJfiG7IhVYltXZlfBWVpVgxQE0DXOtXzCdOuiHGp2otPvrAknncedIJ
nVJ+bvoQjVFDzhZdIyc3WUAaSKHW1hVnsEEDEBPNkMqXqGDi3BksJ7VIBCbB
aSckSVmbUUtS25DkGf1cpRdBSFkvkPF5RixnqJOZbiD96rOfXALeVY6mO0jk
UOilf6z0PvK2NgG3UNsGAV+OmCYfRlQupdGUa1nwVri4AucYIHml5Z5MEpH3
HHcmOwCWjhnK2rTtphv6yZlkgHPN1NJYp9SEn0HgEusk1Q+MUcDQceIyjyPk
0NiYi+SqjcGmhHBPPhzPX0GWu5+9QUVJup8R0lQAxKukm2OtbG7uzYkYvtBI
vigl8wEVFl3kYzZ6os2HZDmK2JD2KA8Ue9WEUIoTnC12sB4Wo6etwbG/AeFR
4uC8I82BncZfXyUfrHDtx8FBlFMmO7paTYV0Gqvm2DIssLgWr65Z6Jrq7IDq
21CCRWqRuBFCsrD1QjYsupuXtTQEUwitdXMX5TlBYyhvHXf4dBxhTddFYcrC
iHCDhIF8kEjAvqC9QYbAsYEqq9oaKhI0YjI7OERJ0JeSk4XiipvyFERpdfzr
qgzB27bQkMNK70DXN7XynOGxYyty2vy8qj92KKZgDREZzHujTjM+m2Mp8DG+
0VWoFZyhjXMqO9Riw5DTRLlTG1LJICXRQmsGtmBM6mxx5yjvi1UVfUjIxeNj
6llplWROiY2IOkIakzVkkw5aU2UBJy6m2ArU8ZGUDviSm6WS4JWZd1pv2X1K
pjrpkmwiXmp/KpbiXD5ezVTFD/aYgDCGGVAStjp9JGN1Fpiyc4gApZPma0ae
QxVPDH5LRLqxnJCfPkcvHuYpqZSOqb5It5KQh2gXGsmAMFoyFnOS89TLlYnr
V1BoWCEKVlQqawXCdLKwvsx3lcgoW9jClflWhS25cL7ISexM/juNZ6FQfO5R
8Ad3UlkZB7A6NMsUzFHDrEHpdtziuFVtjiQlqXhB4YfSypqO9GRKCq66gki+
NW1I0IqCsP2YsJffa55SUjJgxEEVDGZwisbIMO7vJbohHBx3zy8OuueHv/xC
YiDF9AUXZ8fkIWO8KxoSJSEUi1xpJkBiHMgkwzyV1omtTOnKHqmlBYKIpONM
HtqTFRktbdibVzZN275DdY7T2nZa9/ff9MPDDsYKSahHaNbAhLVRSu1MgfSC
2JNcZV7yZcqXFTG00Nj7nf4Md7glWs758yjZjBaQ4ba9Wo4WAokLdZ1mmMvM
yVBhshTpJjbHAAoYV3wsfLIiYy1m51ZxEzGc484UeDSYcuElZm3Zo8n5D2vU
RWV9Ek5HyByIfpmPTSlm36rSkLrcRlvisM1cI5vuwDkF1jekmTGdoE6PQNMR
RZAsrb30Zbx/UfHRn2yljCYnefODJeZc+MnjEZsOMh5/uLI5NostWzVNPHvO
UG8oLR8bnTjMtFNbEIYyOtYJHGAhoO2oFrtJ9h42PzcsWNsv3qft1ptRJq+L
0DBtp46bW2TJQnPQJ52WFH3Na8rASRk+mXaaw1iZCTaViuKMWVQ29FrVg1VD
b26800JXUbH6AhmGPsn8wSIlqPZVxCVXXql79Cj8k44aXQDW5Rjl45y3j7HG
wBCM+CabCuyDS0TYyF9xLrPxjt41eQs4WYHzClIbJ2BKxReVBjLGQmB5dKkQ
awQvtMAjSGe6tEl3GEVtpoxlWMj4nskvenCJza1YU6Jv4tOGDymFgj30Wnbw
Lsd0e65FmEKC6BsM80XsbEIJhAqKtsmdTF5u0Vhm8WVDKS7qOUOlB48u1Q0q
SlKipgsTK10KLL26MoJPwGFMFpLvX2ZQKG4oSW+57KIeAxt1sbakgEDdMarv
llDwoNfOM0zSCzrMtQUAG87p+X0lK6PDvlcUAFNGf3//9uTy7G046B2c9y7C
wcXlPiK80ICk2260HuciCr6fASJkSC9UTDCVE9aILpZua0vkQMFpEJ0oOB88
mQUwhxLlA0LdOc4FXjG/WRZkn3FhbiS7A10rydpAcjBe0pOjg6AUtxd258CN
khSIE3LcaCn6HobBE4hNCyan6ir2AgOQ7uAr6M5TXu7thGoFHJOpWS2QlZFr
bTHjlKWSr4r6l+CZug8D5eNCU4FW0xGoTRKpkaXNU60Exb+s4JkWd08SHA5o
DcUkkYBL7ThgrmgGh6DUSBN8R5ikxJopwoSMbPGnWOL9bHxZbenQDnUrYT+y
eiBaOGcmKpqAK0gFgEe2hbtg/OiYzCwCEcmp+IlU6ZlmI8R4lJR5WfixaGq+
j8MXWEDJlmI2ZVIuKGxTVFtuarQoXei0qdeegVCMbgC+23bw+YIyGIfKI2kN
gWW4cyIaNgH2o9xIAqmY6Hoz4eER6TezzVC4mBPZAKEPjhvseFZydEmxEIXK
RMfVQzgP9CfdMRNbmeXJdZIabDraDRg6LEYNN4S0GipKFoQ1VhY8YnMDsTEO
1MLQNWy0ChViEdWPwrTxlWScvXanJqlrTDRZxGGhWC14yqaG+OoKnTNElK5R
nuF0qNok31ZxurhRKAYWyCdZYREgwUao0WoaZeTNKELTeCmbjhRdlSAuJ+y1
6nQmMAGKJncoafE1ckerXXp8yJo7yzuKlswow7e8OgwF4Rb+B9vYKlZ7W+OJ
FLTSymPfMBga0VbY1b54EU2CTmqN/mLsPJpfNVKLpXQcJSbtVPpq46LTOtLZ
cVyx0YB96Sh3+dB9U6yDBmGjzpzaHa19ipvHNIleaXFyrUYNH1zUIsXEZiyU
VDBnQzdxaarInoSTJrGk56Zqh55ip0AIl4fC2jjqZJD8exJTY10u9NwB+0rA
jYXdumgV0ekwZGmO54TyRwsY1Ycc0mS3AlJcIxKz03jqq3GkvKEla8n4BZQz
kHESgiImJamwVW8KYx2UxkwOwODoglJnfHN+dLD95sUbU4vw2D5/8Wx3xxYc
ajBJ4weX6aJAd8yRJIQqqKwiSVuoclPpJR+96keYkz0QWY2x3blpndlEmyHH
K9AEqQ4WYyEtjPHEKEtcfpibwjVCGTNysf14wYpSsMtODk3NnIkOMMp/UjME
w/kaEhkxG634Y7LDcXpHFmEyyYT52V18+2AP0ap8XSsM/g5Km3YCl75Q9L4x
epgqo2r/NEUUMDybwtmbDcwCrJKbKMXL9RWaJE0sGHaekjFzwcE00YjEfvIS
3kiuVCOuiUmzYZKOMXXkOKdmTjga21GaxciOlxjI/k7uXlvLGcvfFlLR0xtT
qm5fOXY2ZzL++oz/e7hFcHS0HTiG90oCPUKQAC+r2naf2QKaGrWkETxOVK6b
B9pUKeI8T3eR79wqTVSoJnnstA5RKEHSt5irdEY6r6w78Xl2i7jz1ByNYSiV
p8jJDS9+xZMXVmYqLJhfMEkqhxMhzEICAQKvSkdkooVAFhqocHHgIYDY5FHJ
FWEEEdRZqBaxZVR0b0TUumIGSqhIZrQLhIuXmIR3CVJ8TsZHzdWgxOJ7N2bA
KfDmzfQXonmkIRNa4BOXz2rgoTA6IfwTNXfxdrJYZxJ8MIqUw39B24tzrthr
ylA76WQJalp4FI4YCHtWePduEz7ymu7UOF7tjooQwhnxfMSIkYY4vcYotnMQ
DwOpCoqzwZohiU1QNYtLWyLRDHHG8EZYtEmstX4IzWdygTl6lWD71B9LSGBL
Uw0NcFHv0mEVbK6QQa7Iw6PgpMAoOoG6xum/2JqAhLz0mTOrCo9vG1US277k
NftdWh3Fmh1N0RgbqDJu+DBrIftuo1lebRNTaFSaKrKr0m1K0mfXR80DwpB/
1bO8/nXTqzMYiSRD1U84uVWmFhhb4AjnT4hoiWypnaJNDt9ZSgBAnDopJC0k
jZVraYbmzyMZJWxUtsEiW/65ZEtoSXYxXzuPnAKGfMVwT4bHhy84DVyws737
PMQQ++H5oDsMpPxT8x1g4AvV8twONjcs8SH+I8KwaqAbVGuTy35WX11RBnRj
60+a/MMV5mNN4e4UIOGgRaLGZlEqmrGiCS1Z4LappqQEeQkSxhREtsTNJbpe
SKDVO/9ve1+y3ka2pLfHU2RRrBYhEeAsiVSx6oIgSILzPF1VE0kgAYIEkBAS
IAhV6e689ML9eWN7YX+fPy/8Bt73m/QT+BEc0xlyAAhKde9t283bXUJmnvnE
iRMnTsQfJiJEvcU3OnzZHNIQhEw87ENrxW/i+QkVzMgY2UGk2u1znBsK/0Uy
gH6JTqd4bNzwfWX468wtZBey87STqnB3LR3taHbRRL0jecqyXgPBgdh2qLD5
7GL2AzOx5BLn3rHIJyD9aoioFuIeYvOJFdkkTuGm2JncAN/jjtEGOgX6nZKq
f5IOpXXDO6IvDamibmUkvUoYL4sjpfMxgkV6rg0kFtb2aGWlPRHirGUBqTCd
WJNq9hEo7Q0S1RvHGBKK6KJBVmK7KcLMm0B04nPFdvjKM7YLglyZfdMs6zQ+
/1lA9F3nt9/WiyeHu7krkNAyxo+aogTymMWiqgokMR07cAPUFhIS/U+MJQtP
7YbEwkB05pBAEYNtBxHD0+kzaDkUkTMi8DWxMSHtPGy5qKjHOwZxew+7w5EG
WRSodO42YqWFjGMgZG0vypaEdIyGx1LRM5TtP9v96DKCMN66sbeOePmFgOTS
AhxD3EY3MdwwS8AOAcBndfxnMmxs46l5Ws6lGpWKr0/lJEqqII5RIOEbzfVv
yHVU3IuUaw2VmZRAx88w7kSBuYxgzAWcAdpftMJHKQZeE6hMr232MWhMxbU1
XtFrjClWZIl2X7gA4mgrwSMhwGA0F3AGaPmdht8O0NtVwvJUKh22J6kHEiRn
JIURjFsjhApDYRLcaOgIIvmWhpPSdgkeRzLguy21dq3ESo0qcPRBmBmE5sKK
fZBBoZ7W/Xvb0xVbzNcBwLxxdOezFEAe1Uga21h7hizS4LzLWqUtJJe25naw
tNnscva94CmwwPwYzxdgeYankclzm4UVE29geTFc/Bcsfi47Z+5+lfkJ0X40
f7gKvsC/c4M7q4b5ebuGo94T1bAM47E0pJJwAVjFad+PxVyYltgbIvMrpJ6E
0F6RgdCVMlwN1caKhiz5HCbwQcXkwtoo2ApkMbHPXz8xqytxSti+1rrapeYT
x+n6isi8CFCFXH2kh6KvhH1kZUWEwN0kvAc0/ozPV6VMpuLd9mqlUIS0mHUZ
l6V8A1WQkCmlaeh2etxY6/A0bODSrGaPio19V4XPqNtaAwt4xIoNGsa0iHrV
e3IUHrCJR7mLgsYpR4Lz2iy1K0EGVURO0PRp+EXb0b/zkRso98gs2r+Swtw4
TD76eN84HY+QjA5IeimTWKrl+Wl1QJIMYh5m8lleZ3jKDynG4eiuooOxko4D
aFoCWx3v2WBVYQq6yUf9udbQoJmomjbefOxjvQoUA41ANZqsHrNs0RAGDxpM
24RqQGCmrTDSHfDXOrMf3GcC5VihY5apeqLF02ZJy6LXwXlU9yWcH23L1BBZ
pyNfhVvLsWaDhoevB4Z3VPkamMCPCb2cfmE3VaG00uR+25TKhcb66Bo9PXWT
CVJsX+qdITsxllaBIxVdfvsN4CBWT3g4wmcqEcLZ6pzCsGLOCtoedFA/Zu95
EaQitxXaPuk2fiKyhcw+rRdy62uFwobN1wlzv6XV5pFYORhiVZTQeP+hhkNZ
Y9R82MTZNF5ZWNlKBj453+H+gMNaXLfbwEZ9IOXJnLBaSZiBvReygKqMdGku
BsmjEkEg1ppSuwmCGayhvaDdNY8dGuUExVWRuInhvNgSB2O76yp1mAB0jrQt
zRAfBpiOKzBOXO8O1ZsmrHlxkRUeaGlyWyQMaP8CZbFEFlAMRSi4wfXQ+d0X
pC7FiAmZwMJk1HRbxziafBvJDiyWhkRjZhBDlfVIa8DMeaiwmk+FUcRYPO9J
k/Ey2Zr925ARnsAm/zEBKFHBGI1+ZVChOqyWJtcz/SQxfs3VOOrHtXWcCStl
AmWQSYaojYFjNdgOUReYTem6xDBNRW6iRYvu/YSA6w60iwIJDmq0MubWQoOi
4ZLQRvH6NVuyktG4fWy2zFLjeeiwi9/yx8W9glSaNrJE5JKfb0bpxKbdVFv+
qLaGFbFsv0pHv7A2QQ2YU+mRW5uJbkUq/kM0tSrHNfzalNyOsxl2s5RTFVG8
QErCbgjSjQTjQ4gHjcIXsHtkR8XdVXrlEt50lmCRd9F8No3MxrUw1ezJUwYE
PDg4G2gNE/jluvIqsidH6jXXvdpYn5VjhzuFkx0FO0fA84J0uQQivI10mYZG
KZRqg+NLrvfE5Q/PjtdYegHx8K5egWoyulYMgYHosyyM6fuUxyDLxmkkuqvX
BjJEjBPxGi3pdoU3jgABUhqwSTHAkop6x1SpDLIpo4EGZCambsJFo0MM28Tb
C/j+mqOSoEotCT+QjYMs+yNtAmBsNtwuW/KVB9pZg/EbOAq67RHJI4F2v5kM
GbcjbQK1PepjXR6tzryGX8PrH/iQKasXX21UbDJKCzz4Csd5H76SZgzxK8Rg
lorQV3VYUomDV3dloxOBlISY8h30znHrTeuIy+hD1HggmsLeeeH461fmfaEG
z2XnVVPhp+DdQWX4Ho7wQexGIIy2hXdFYfsro3CRyNGox5HDj4q4ktSMOdOM
ua+UM1FnpCB35ISuzNV7HdTpUOz3EgcdfrYEslWiWL3iCaCGm1xf2QbBUzFR
JZIV52z77V5DY7Lp2Niw9MlPRcCtEuLHf00n9XzW9Hz2azSKi6UUs8aT85as
Z9SHqcewlixF0nR4kqoeS01U5EmCR5Zc7bIbn7j0Ke8yJcJFIvzgGS5+tEss
XxcfGD2oTI6m+ejcaZRYItBwH5PuknE09vQVva3CQshrO5y2bihwRmBPGb7Q
Kylmia8IYM/CyO8GuPLzGKiGLCxzh0Vn6pQlkUcvDRPaqN9CO9nR0kgNygSa
IkRMczxoKxiICSwBK1Uj0dQlKoVImkC36H1GFq6PkUAg2A4QdP1AnSl16Bdh
GyoQjEL/tkKd8Bn0zrUwedV1fjbwERI0W2k0BAo0WxlAUSW5SiM+rCVL9L1p
0sUTF9nVoTSgew+6dIUpriUtrVNUiDt0R24ZxxOcFmG+EKClHMsSg4zw3uRM
yK0dnE5gvNRg8C6SUz5ElbBLjTVosmLYplANqKBJSmTZU+sasua7DQNjHxpJ
U0PdhDiGifXcYCCg+DwRzG9tcrDcNThwu01HstWLQBK49Yq6byFyicTWgL2U
CBQxljo12HmaINsoO8yWhWmjHbNA2qnSCJizgljWkVmS9gQ0d/o6VjEbvGpr
IgV6NLwSfXNvKQyt8FoNs9amoRSKeCIzqGIKMJ4Kydh8L8LChbohVBXJtNks
IyOaWwq1QR4QaNVc0fwme1fi4Fjswo0mfmTmtDrBXye+pv7yl7/QTerME2zr
lU5q5o2TeZMhKl1xyh+RYBqZst/oNVsrzrvZj/T1zUzqVb0KU1R1bm6AHZzf
bN3cpF6JUbX1CpKJLd5PQbcCY5G9+zn8Dg9P0Xe3yEoiLwlJIvSOQ3TjO2x0
nrgI8mFtGK6n6jw2ZBKdBPqBedc9xiBESWh5md7ia8MCMjKw0+To7rfdz70Q
MDtlwetmHBGv1Ws6v6Uc5JM3BzvOqjM7LU/F/dPC8X5u96ZwfHxwDF/mph2o
aN9nOZEsGWEnzO8WsUSV5zy3W1zHqLaQYf75DPYVEeRYUJUfHBaOaV+6ye0i
2snVTeGykD87LaxDqsXnyx0RNxh7outJiASM39+r71aYXny/bAYnMR4vdtqU
HYqui5909hGYLjgKc9MJ3eAImPhZt04FuMUx0XlCMWjhy5IZVDvGLH5ZjnaT
TOHgyztdWjRoLH58n9Q8E6UVkywnJglFZIVk73U1ESd4/LZgN8GKT4rfIvMQ
jhEKCT4sJNUvoT7xuy4gMbAmpFjWnUwKYIm0MKsbH4n7SB/DFBYJ4Egp3if0
TwIz0ndoIiQAQmfAKtnnWR34xTNg3biC4axUoYMf7jM/mGWwl7vE5QvlwWrG
p+nUV1wsN16n8xHSDGEEOMywbG7WivvQL5spqC9CW3N/QBtVkdC6eDtRnL1x
g4/M5OgWves228TEkOtBErJ60iBKfGAw7uys8Q/kahi/ne0XL1MONLntg4Q6
Nbf8fjYzOwf/dzo7u0L/d51mk+d3bDGkrNHRDBD9nJw3mD3Bsdpu35RScRxv
5B3UHzhuF7MRznZaDH0YFwZvM1pSycI8VSl10a0u3gVDIsxcRRmAwPjExY1O
73iWFSZ4w3FuuIXrXtBGPAwUk1gTz8jGgQeSD2wWGsCtiyp01pxgPizjpjtt
Bld5cUlEKSV9IHyw0pv6LcxJ93pup4zIOBLTiAuTkMZJfZzGjNxLUnR2fJRz
HskwxZmfXfjAVmds2wFVdxSCAvUbM0PX+c579JSoYbkQyO4+o6FIHwXeQDCq
TRcNZWFe15mATdWbwAp7ngWNyF/66oNyJiEEaczI0I0oMtZddtHGoWp4NRj3
Jp35KZ/CENPV06hqOc3uGHU/i+tALWEY0HeLN6ZPH7WQo97cYOOdqSn1nJ6C
5QZ59or76XRS6n5y4rdzkJwlGTavVQc8HuECHv3w4GUi3LJNIepzWP4vh/LR
0V8IwWtpOFCQ0dHYTvt0isGSKRlPKjD88ILoQDRbWv/UtPCy6V5UalWUkKOi
wk1hf2exvoI1DCeRDLpCfTTaVMyKiOJALAOVkposaLHaap2zB1ngc57nTFx7
HR/z2s5qEzpgDGz/ewVl0Y/J7rrddrAyMwMkkn0ARuE1sn6nNtPu3c4E5eYM
HFx6TzP8AdPMPLgDeAmtKmfhUbqIovMKKkBSJPZx8ACa4XL36SboftTUE/uk
fgLvlV9v1I8bvFScSn9M4f2YflnteBgXmp+cN/ADUiCR7Po1dE9fGS557h5s
3uwXQJKy9xp8aWRP6yXsxvsgrZCEab0u7m8c2DIkvlsvrJ1tksj4/RsVlpe4
STX82k0Do0LiUHUldCQdLEmbQUhfDg+eTnpDjhhToXeO/pWGkVHLERjQ1BNd
/0+ZlKuruknOq1cOfJdIyK+eoLWYhUYu/VGeZMj0M46VfqBBgqdXPTolwSv6
QOVNnPG19sTH1FeazC3GqZY7Hz4KisEprBxc4bi8HLO+kgCWCICfzcoRTUFf
QkMHMaOGmKYdgd3iRFOtorMrUGWjPJa8PD7hyASiWnT2z3Z3MzreQ4XBtmmt
he2fBPiPim75SUB9ioVgJYQIKdv9hENu6nzNZ6PTUgvleI0qWsyMml0Scryu
IYJs4spVq4YupKfeKLLBUUgPpSJcCKP+qLA3VuunQwQLFCGiYspupR750FKf
duw20fQMqz5WLVQEhHUi0VgbzC1Qd3CLDmYDLXHhYRiV9pr28NYTFT1PMnTO
1K3lx6jfY+Z6EGUf0wpXN8xA0JEQ0ocZCNGhuDeRS30lnTxPSQPGszJktPij
bipyTFpmxcTrRaGgFaUMQB0LMRKkb2W/JrQfj2lJl5CoesB2TwnqDqwJe0ko
+EMge8GRRMspxA+AtQNMSIheVE0Km9WsYLmd5mvZpBGKsUTV7OjO8Uz3lEbQ
8sYR+Y+a6PuNB9ixp0zLTbOhb4TG0IqEhOq7AQl5yb2SLKod6Rf17kblTugl
OtoZJAEQRVifqPpr32UaoEipmjZeNd6OvvHAPBacGgdAoIAzlM9DZbYo/tQs
O1PucFqgIVVcUHKkob6821IbRcIo0zUk8XO/I5gIdM156w3ICssMz8tI5UaP
UZK0AfV6K7Fm2Cp8NGk1VzxYbwYDvZOfg2UJ4trxGAXZPgSuRafIJ5HNg0Hz
1m9oZJKwblpp6fK7hRxF92JPGZ7OjtsnK4W0tazVLaY2vb3tkbYdBRULDd++
lMfWYL9gWhjTp4V3G+JDxfpdhZWlpO5b5aggeZWdOk8p7rJKfNZXHIlMz4iO
0MxhUiV/Uj9hrrTwiF+M8AhPzhv4D24/IJvddHUaEtWmmCoiKfllD7beD3AC
eqOzsNNdYhaeEPJNlpPDCg+8zJmlUsDzSqMhZgF+1T7+50OW2yGcmUM2bMBA
NGmOm13mdUvHT8I2Mg4qrij9jX1Hw73FC34+GiMxYNaoBJN3FG7xMxND8VeG
Cvzy0TzwUuKgmS20eGnZUDh8khJf0VuCL4IuEF3SuqGTnGyZEjQaQRwUJXqh
YVdNp/4y1Q/tJY2imJtgInxRDWVGsR2/TCftgXglZGA5RN2hZoB3RxH9xEbG
DA6uhBsJDRHd6KMpInv9EDEoQrKMiMEUj+M9OhszRSaRIQl1y5w3b0B+CJ3W
pMH6vMbJ6B+1Mo69bsery+0nVqkEW1EaWaGO9PjhcNpT+zpQVDxkG+ZpA6bG
YgW8TKIMRdRzQ0a+hoIWlWStdLtPQ4bIHkoZIhJE9Q37ixiDqKI0YqQ2DRTT
oudWaFCvDV2g8k3/ljO5ljTx8wvp79vIT9UWpylpgyIpToT/1SJtyNwAJDO2
RsArrml97xqwKm9ae6LRkBl/0JXnRjFkpDBsOKOJ4i/t7Smc2nQx9N55Q49B
5NAUzlsmkCiLSBOLGHFsk/mRsUeNuICva5o0QRZCZU9rmAiQJXEAzUU3yIDh
mZGU+d3is0eccPe6/g1p0r6jg47ZpU0nWRwJkm4l66j2rHhPhMTUo7tAUjUG
2dFNRZZBet/vaquaD2qCpTD/3qbLphb27q4bXHzjndwS3+NpZRExTEFp4XC5
0TVme3A+x3Hjw4i373/4MMq9j2Ox5W8aym/oD9uaff9aHd6/0CJ+vmsy6VTh
DfeTN0xp6VAqukIjPTIICW3d+uhIO6RsanTcYfNmsnkin7AQAX77WH73KMqI
WSMwZg57hJ7LEhMdrAkSs98pRhpTDqpoQmv5p9KlRdXHapTBlLLJ+MVhe7hw
xNM7497AdmYtzIuAdOLPZFvto/uaBcYQ+YTqTcysD+nEiFmYTatjpVjyxcMr
B7KtjtxZ1eQNhu2qdoLwi4i4YhLSPUJcMaYTxMUMk9dsxFZy/jc9vEK/eyNo
IslZLS6Od1GR7TxcEMcE/r5y3ErlRjluDSlpFN3GiFbKEroF7tHyw5IAXT1r
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
U8Oe5JI7mQjYlEqJU5HIV3IFjIP9bhFPtD/bmxGTSC5XyOf6RxtrtXIxf+Tv
rudmD9afcseFu72zjeOry821B3fzqV/ZuvtQK54U77fzZ83tQa29Uw+C3ZPF
x9TeemGw9+Vobv++vHhw6r8/XJ99ezi7tnb0sF84PrveOik0dk5mn/ZPH5aP
zs63T883zi/O5+6uLxrd8uX5UjV1tbF/eLZxVXMv92qVzbtGcWN/9uryuHG7
ef6lPFg7LG+e984KlaPixnWj3Gw03Yv9u8pm4/G2vnZaudj+krq+PK033fO7
q+b+w/XFdcvdbHx255+6t83lfvly+0tl63y+snC3BJLqh+rl0kytuJmvLZ5s
3PlesX71eTd1X5w/uF/KHz+0D84a1+5lc7vpNpcGlVb7bc13d+7bOxfN9rt6
+/PnXtBx3z0Gu5uD4P3JXLfjLfZuP79PPe7Ov338sL7WDw4LT+XbrcFea2fw
4cv+l2DmaLayezq3f3kxt3x/Pd99LC9U3lcXD7bqi29PG0u9qv8O4WneHyz0
3s+sP314PJxdrt4uvD1svXs782V55vED25PBpqY4HMEMZmc0w9NnzwyDnmXE
TV5YQkig4DnP4N9aYbO47yAJHZ6t7RbzqNdx1nYP8jv0OZV6ut8rXNYe73Jr
V9s7/au1tdyWe9z/sJY7quQC9zTYv2+6+atBY/Pg4d1g4bp291Bv1D5vXr3f
b7y/3GjMp3ZPjk/O6l/2N7aOfZzcq/nzQSW/1oZJbXhb8G/z/KHvFwqFp6ti
Lv+wUWss7i4e5TbyRxcPjXe5fKrZ38tv1XIXxaPTt9dXs5XaaX2rXNk9mCm3
nq5212e/VDdy9aPcTv543TxfdXdyR/m7q/puPhW0Hs/PF3LXZ9314kb15HDz
3eHnz1e9043BbP5Lf6OW2z5+V86tv8vdl88vLoODi9y7w0ZwvXjf9C+OL9Yv
UjOXR/vFzc7B0s7hzuLO4kb3aHY1tdo78uo8iIX99RFDSBPHszBEPkucD802
ZCL6rbMCTEIxtza7UWtuHXzYe9mQpOpHb73c4eL8vbfUf+zm9xd3qp97t3O3
sMbrc4WHur8Ng7xXfizMFqru28X31dr68taVNxMM1vKXRxdXqdzx7fls46B6
urfeb9QvgqX+4XWv3TsI1g46g1wAQ3J6dnkfHpJIL6yxGCqtfsNoXJzkii8d
jdPZ+9zh8vV1d/nsc3Hx8LpbrNevgsv69tLS4+nM0uLOxmlre+6p0zl+2tsd
eCf9Qu5zf6P65fKxXb08WUp5O+fb5b3ND8ufiw/lL9fF4sL8lft26eH2bHY7
OKrBaNwud7bGHY1kEf0bxqLR/wyj8cKxuMjlgDK6p7n906vcu9u3y835M2Do
7y/urmaP3hcba5dfFg7b971+dbG+vPu0nVuf8donj4UPjfONraNiqj/3ePR4
531uFt2F7YPdu/11r7Vw8fhh6aR/utj3YSy+dHYPxx2L8DHkj2JWnbP6zod2
kFs4Wzj60KwczK1fH8+fXXy4rF2urS2cn3e33PtUZ+7MPduo7m9fbN+V588D
92KpAe1slFvH7etm4x53pN382oJ78RQUN7cbxa3tRqW53Lm+OM17/aPT1Eat
liv2L/LUitzOba5f9KA1d2tbm5+bmw/1mr8UrFd27mv3D3NrD4WHnVb+PJfz
twvr/JzCF2f75bXc/nE15waHg6XG5eXGZfBQvVwcDDae5vbmHp4u594/PvlH
hfXu2rvTzmfgdKeDL+eLj/dnzdTVQrfWuG/sf6hfX1fmXCjZ3bq6ete9O9z5
XJg9y+VrqzAfF0Gx9kLmFToPfsMirZ5d1ftAmMdPn9t37aK/c3CbWzjxF4tL
+0fXa9v5dr9BhJnTz6lG9eJ97mj97cxB+cPg3Xmtfj+TP6ldN9+u1d4vel+2
l+d23lXzJzuN2l5wWZ6pLeUKucf3Mw+73txmpbfUSxVz8++63rtB97C6nTvz
68WZ00F/6erq/G2+dnyEhOnfbi29lDDDV/d/DwLNe7mjGtFa7iJ/VX7f7+eK
lXHoLKUIDV/0a4XczHFuY2vzYmvtvlZ47N7deudzCzPVSqd6kn+7dNzpPG4s
zbrzd+7lWq8AUzGTup4/WyrUZh7cpd3OfeVwd3BdLcy/vX//9tY/X/9QOfo8
fztb+/B2dv3DbOOqufHl+uKpfds8431/s9FMseR2FhS3Ku3bzX7tCj6CEDB/
O99tXO9tv19b27vI53L3MERe/m0hl2sH67m7xdxGvVAou5+vUu7JTv6+2d+f
/XyQPzg92zw6Ofpc3kbKfjgyz+dHc8Cy5zY+rH3uz+w2zyvlc29wvFy9300V
L7fOvlycblQvezObd7mjg9mt9kHPX8ttH+7uX9bf7p9c33vz+YuDs4XBdqOx
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

-->

</rfc>

