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


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

]>


<rfc ipr="trust200902" docName="draft-dkg-openpgp-prompting-caching-00" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title>OpenPGP Prompting and Caching</title>

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

    <date year="2024" month="August" day="08"/>

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

    <abstract>


<?line 42?>

<t>Some OpenPGP secret keys and messages are locked with a passphrase.
An OpenPGP-using application might want to prompt the user for the passphrase, or might want to permit the user to only enter the passphrase once while keeping the material unlocked for future use.
This document describes a simple interface that can be used for prompting the user and for caching the results of such a prompt.
It is designed to interoperate well with the Stateless OpenPGP Interface, and to facilitate its use both in test suite operations and in common patterns of interactive operation.</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-prompting-caching/"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-dkg-openpgp-prompting-caching/"/>.
      </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-prompting-caching/"/>.</t>
    </note>


  </front>

  <middle>


<?line 49?>

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

<t>Some OpenPGP secret keys and messages are locked with a passphrase.</t>

<t>An application that uses OpenPGP might want to prompt the user for the passphrase, or might want to permit the user to only enter the passphrase once while keeping the material unlocked for future use.</t>

<t>This document describes a simple interface that can be used for prompting the user and for caching the results of such a prompt across an interactive session.
The OpenPGP Prompting and Caching interface described here can be referred to as OPAC.
A specific command-line utility offering this interface is referred to as <spanx style="verb">opac</spanx>.</t>

<t>It is intended to interoperate well with the Stateless OpenPGP Interface (see <xref target="I-D.dkg-openpgp-stateless-cli"/>), and to facilitate the use of OpenPGP both in test suite operations and in common patterns of interactive operation.</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 tries to use certain terms with specificity:</t>

<t><list style="symbols">
  <t>"Certificate" refers to an OpenPGP Certificate, or Transferable Public Key, as defined in <xref target="RFC9580"/></t>
  <t>"Secret Key" refers to an OpenPGP Transferable Secret Key, as defined in <xref target="RFC9580"/>.</t>
  <t>"S2K" refers to the OpenPGP String-to-Key process for deriving high-quality cryptographic symmetric keys from a human-memorable string of text, also defined in <xref target="RFC9580"/>.</t>
  <t>"Session" refers to an interactive user session at a computer.
Different human-computer interfaces may have different conceptions of a session, and this document is largely agnostic about those details.
The salient features of a "session", for the purposes of this document, are that it has a defined time limit (often bounded by operations like "logging in" and "logging out"), a way of requesting and gathering feedback from the user ("prompting"), and is intentionally under some overarching administrative authority or control by the system operator ("the logged in user").</t>
  <t>"Fails with XXX" means that the invoked command terminates and yields a specific value associated with XXX (see <xref target="return-codes"/>) as its return code.</t>
</list></t>

</section>
<section anchor="theory-of-operation"><name>Theory of Operation</name>

<t>OPAC is a command-line interface to facilitate the use of OpenPGP, that binds together three things:</t>

<t><list style="symbols">
  <t>The user's interactive session.</t>
  <t>An ephemeral cache of OpenPGP-related data that can "unlock" OpenPGP objects in the filesystem.</t>
  <t>A session-specific way to notify the user or elicit feedback from them ("prompting").</t>
</list></t>

<t>The ephemeral cache may be backed by a variety of different mechanisms.
For example, it could use memory of an ephemeral session-bound process, or it could store data in a kernel-level keyring.
Critically, the cache lasts no more than the duration of the user's session, and the material in the cache is never deliberately placed in non-ephemeral storage.</t>

<t>Since the cached material is associated with objects in the filesystem, OPAC tends to assume that all processes in the session will have the same view of the filesystem as each other, or at the very least that any process invoking OPAC will have the same view as any session-bound process that backs the OPAC cache.</t>

<t>There are unusual computing scenarios or configurations where OPAC will not work correctly, but it is intended to work with the overwhelming majority of interactive computing environments.
See <xref target="subtleties-and-nuance"/> for more details about OPAC's applicability.</t>

</section>
</section>
<section anchor="specification"><name>Specification</name>

<t><spanx style="verb">opac</spanx> uses a command-line interface, with a set of standardized subcommands.</t>

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

<figure><artwork><![CDATA[
opac version [--extended|--opac]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: version information</t>
</list></t>

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

<t>With no arguments, the version string emitted should contain the name of the <spanx style="verb">opac</spanx> implementation, followed by a single space, followed by the version number.
An <spanx style="verb">opac</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">--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">--opac</spanx> is supplied, the implementations should produce a single line with the implemented <xref target="SEMVER"/> <spanx style="verb">opac</spanx> interface that this implementation specifies.
For this draft, that version is <spanx style="verb">0.1</spanx>.</t>

<t>Example:</t>

<figure><artwork><![CDATA[
$ opac version
ExampleOpac 0.3
$ opac version --extended
ExampleOpac 0.3
LibDBus 0.11.4
See https://pgp.example/opac/ for more information
$ opac version --opac
0.1
$
]]></artwork></figure>

</section>
<section anchor="get-password"><name>get-password: Request a Password</name>

<figure><artwork><![CDATA[
opac get-password [--message MESSAGE] [--ignore-cache]
                  [--prompt-timeout TIMEOUT]
                  FILENAME
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: PASSWORD</t>
</list></t>

<t>When successful, this invocation emits the human-readable password the user expects to be associated with the OpenPGP material found in <spanx style="verb">FILENAME</spanx> on standard output, encoded as UTF-8 text.
If any failure happens, it emits nothing on standard output.</t>

<t>If <spanx style="verb">--ignore-cache</spanx> is supplied, or if <spanx style="verb">FILENAME</spanx> is the special value <spanx style="verb">-</spanx>, <spanx style="verb">opac</spanx> <bcp14>MUST NOT</bcp14> look in its cache.</t>

<t>If an associated password is found in the cache, <spanx style="verb">opac</spanx> <bcp14>MAY</bcp14> ask the user to confirm its use before emitting it.</t>

<t>If no associated password is found in the cache, <spanx style="verb">opac</spanx> asks the user for the password associated with <spanx style="verb">FILENAME</spanx>.</t>

<t>The optional argument <spanx style="verb">MESSAGE</spanx> <bcp14>MUST</bcp14> be well-formed according to <xref target="message"/>.
If <spanx style="verb">MESSAGE</spanx> is not well-formed, <spanx style="verb">opac get-password</spanx> fails with <spanx style="verb">MALFORMED_MESSAGE</spanx>.</t>

<t>If the user declines to offer a password, or declines to permit use of the password from its cache, <spanx style="verb">opac get-password</spanx> fails with <spanx style="verb">USER_DECLINED</spanx>.</t>

<t>When the user's provided password is emitted, <spanx style="verb">opac get-password</spanx> <bcp14>MUST NOT</bcp14> emit any other data to standard output before terminating successfully.
In particular, it must not pad the output with LINE FEED (U+000A) or other similar characters.</t>

<t>If the user fails to respond to a prompt after sufficient time has elapsed, <spanx style="verb">opac get-password</spanx> fails with <spanx style="verb">PROMPT_TIMED_OUT</spanx>.
If <spanx style="verb">--prompt-timeout</spanx> is supplied, the specified timeout for the prompt is used.
If it is not supplied, the prompt timeout is taken from the configuration (see <xref target="config-prompt-timeout"/>).</t>

<t><spanx style="verb">opac get-password</spanx> <bcp14>MUST NOT</bcp14> insert anything into the cache, or update the expiration date of anything in the cache.</t>

</section>
<section anchor="cache-password"><name>cache-password: Cache a Password</name>

<figure><artwork><![CDATA[
opac cache-password [--on-reuse REUSE_DIRECTIVE]
                    [--duration CACHE_DURATION]
                    FILENAME
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: PASSWORD</t>
  <t>Standard Output: nothing</t>
</list></t>

<t>This invocation reads the supplied password on standard input, and injects it in the cache associated with the <spanx style="verb">FILENAME</spanx> OpenPGP object in the filesystem.</t>

<t>Standard input <bcp14>MUST</bcp14> contain only a single UTF-8 encoded password, with no other information.
However, it <bcp14>MAY</bcp14> include trailing whitespace characters, which <spanx style="verb">opac</spanx> strips before storing.</t>

<t>If <spanx style="verb">opac cache-password</spanx> does cache the password in association with <spanx style="verb">FILENAME</spanx>, it succeeds.</t>

<t><spanx style="verb">opac cache-password</spanx> <bcp14>MAY</bcp14> decline to cache the supplied password for any reason.
If it declines to cache, it <bcp14>SHOULD</bcp14> emit the reason for declining to stderr and fail with <spanx style="verb">CACHE_DECLINED</spanx> or some other more specific non-zero return code.</t>

<t>If <spanx style="verb">FILENAME</spanx> is <spanx style="verb">-</spanx> in this invocation, it <bcp14>MUST NOT</bcp14> insert anything in the cache, and fails with <spanx style="verb">INVALID_FILENAME</spanx>.</t>

<t>When associating the password with <spanx style="verb">FILENAME</spanx> in the cache, it chooses the duration from the cache by looking at the <spanx style="verb">--duration</spanx> argument and in its configuration (see <xref target="config-cache-duration"/>).
It chooses the shorter of those two durations to be the default cache.</t>

<t>When a cached password is requested for use, <spanx style="verb">opac</spanx> follows the associated <spanx style="verb">REUSE_DIRECTIVE</spanx>, either from the command line or from the configuration (see <xref target="config-on-reuse"/>).
If the <spanx style="verb">REUSE_DIRECTIVE</spanx> appears in both the configuration and the command line, <spanx style="verb">opac cache-password</spanx> uses the stricter of the two choices.</t>

<t>When inserting a password in the cache associated with <spanx style="verb">FILENAME</spanx>, if any other password is in the cache associated with <spanx style="verb">FILENAME</spanx>, the old value is removed from the cache.</t>

</section>
<section anchor="cache-internal"><name>cache-internal: Cache an Intermediate Value From a Calculation</name>

<figure><artwork><![CDATA[
opac cache-internal [--on-reuse REUSE_DIRECTIVE]
                    [--duration CACHE_DURATION]
                    FILENAME INTERNAL_LABEL
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: Internal Value (octet stream)</t>
  <t>Standard Output: nothing</t>
</list></t>

<t>This invocation reads the supplied password on standard input, and injects it in the cache associated with the <spanx style="verb">FILENAME</spanx> OpenPGP object in the filesystem and the supplied <spanx style="verb">INTERNAL_LABEL</spanx>.</t>

<t>If the <spanx style="verb">INTERNAL_LABEL</spanx> is malformed (see <xref target="internal-label"/>), it <bcp14>MUST NOT</bcp14> insert anything in the cache, and fails with <spanx style="verb">MALFORMED_INTERNAL_LABEL</spanx>.
If <spanx style="verb">FILENAME</spanx> is <spanx style="verb">-</spanx>, it <bcp14>MUST NOT</bcp14> insert anything in the cache, and fails with <spanx style="verb">INVALID_FILENAME</spanx>.</t>

<t>Standard input contains an arbitrary stream of octets, but it <bcp14>MUST</bcp14> be at least 1 octet long.
If the input is entirely empty, <spanx style="verb">opac cache-internal</spanx> fails with <spanx style="verb">MALFORMED_INTERNAL_VALUE</spanx></t>

<t>If <spanx style="verb">opac cache-internal</spanx> does cache the internal value in association with <spanx style="verb">FILENAME</spanx> and <spanx style="verb">INTERNAL_LABEL</spanx>, it succeeds.</t>

<t><spanx style="verb">opac cache-internal</spanx> <bcp14>MAY</bcp14> decline to cache the supplied internal value for any reason.
If it declines to cache, it <bcp14>SHOULD</bcp14> emit the reason for declining to stderr and fail with <spanx style="verb">CACHE_DECLINED</spanx> or some other more specific non-zero return code.</t>

<t><spanx style="verb">--on-reuse</spanx> and <spanx style="verb">--duration</spanx> apply in the same way as <spanx style="verb">opac cache-password</spanx> (see <xref target="cache-password"/>).</t>

<t>When inserting an internal value in the cache associated with <spanx style="verb">FILENAME</spanx> and <spanx style="verb">INTERNAL_LABEL</spanx>, if any other password is in the cache associated with both <spanx style="verb">FILENAME</spanx> and <spanx style="verb">INTERNAL_LABEL</spanx>, the old value is removed from the cache.
Note that multiple internal values can be held in the cache associated with a given <spanx style="verb">FILENAME</spanx> as long as they each have a distinct <spanx style="verb">INTERNAL_LABEL</spanx>.</t>

</section>
<section anchor="get-internal"><name>get-internal: Retrieve an Intermediate Value From the Cache</name>

<figure><artwork><![CDATA[
opac get-internal [--message MESSAGE]
                  [--prompt-timeout PROMPT_TIMEOUT]
                  FILENAME INTERNAL_LABEL
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: Internal Value (octet stream)</t>
</list></t>

<t>This invocation retrieves a previously cached internal value associated with the <spanx style="verb">FILENAME</spanx> OpenPGP object in the filesystem and the supplied <spanx style="verb">INTERNAL_LABEL</spanx>.</t>

<t>If an associated internal value is found in the cache, <spanx style="verb">opac get-internal</spanx> <bcp14>MAY</bcp14> ask the user to confirm its use before emitting it.</t>

<t>If no associated internal value is found in the cache, <spanx style="verb">opac get-internal</spanx> fails with <spanx style="verb">NO_ASSOCIATED_VALUE</spanx>.</t>

<t>The optional argument <spanx style="verb">MESSAGE</spanx> <bcp14>MUST</bcp14> be well-formed according to <xref target="message"/>.
If <spanx style="verb">MESSAGE</spanx> is not well-formed, <spanx style="verb">opac get-internal</spanx> fails with <spanx style="verb">MALFORMED_MESSAGE</spanx>.</t>

<t>If the user declines to permit use of the internal value from its cache, <spanx style="verb">opac get-internal</spanx> fails with <spanx style="verb">USER_DECLINED</spanx>.</t>

<t>When returning a value from the cache, <spanx style="verb">opac get-internal</spanx> <bcp14>MUST</bcp14> emit exactly the same data to standard output that was provided on standard input from the corresponding call to <spanx style="verb">opac cache-internal</spanx> (see <xref target="cache-internal"/>).</t>

<t>If the user fails to respond to a prompt after sufficient time has elapsed, <spanx style="verb">opac get-internal</spanx> fails with <spanx style="verb">PROMPT_TIMED_OUT</spanx>.
If <spanx style="verb">--prompt-timeout</spanx> is supplied, the specified timeout for the prompt is used.
If it is not supplied, the prompt timeout is taken from the configuration (see <xref target="config-prompt-timeout"/>).</t>

<t><spanx style="verb">opac get-internal</spanx> <bcp14>MUST NOT</bcp14> insert anything into the cache, or update the expiration date of anything in the cache.</t>

</section>
<section anchor="drop-cache"><name>drop-cache: Dropping Cached Data</name>

<figure><artwork><![CDATA[
opac drop-cache [--all-subsessions|FILENAME]
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: nothing</t>
</list></t>

<t>If <spanx style="verb">FILENAME</spanx> is supplied, this invocation empties the cache of all data (passwords and internal values) associated with <spanx style="verb">FILENAME</spanx>.</t>

<t>If <spanx style="verb">FILENAME</spanx> is not supplied, it empties the entire cache.</t>

<t>If any passwords or internal values were removed from the cache, and they were all successfully removed, the process succeeds.</t>

<t>If <spanx style="verb">opac drop-cache</spanx> failed to remove any item from the cache that it was instructed to remove, it fails with <spanx style="verb">COULD_NOT_REMOVE_FROM_CACHE</spanx>.
In this case, it <bcp14>SHOULD</bcp14> emit an explanation to standard error.</t>

<t>If <spanx style="verb">OPAC_SUBSESSION</spanx> is set, it only removes items from the subsession-specific cache.
If <spanx style="verb">OPAC_SUBSESSION</spanx> is not set, it only removes items from the main cache.</t>

<t>If <spanx style="verb">--all-subsessions</spanx> is present, and either <spanx style="verb">OPAC_SUBSESSION</spanx> is set of <spanx style="verb">FILENAME</spanx> is also present, then <spanx style="verb">opac drop-cache</spanx> fails with <spanx style="verb">INCOMPATIBLE_OPTIONS</spanx>.
Otherwise, if <spanx style="verb">--all-subsessions</spanx> is present, it removes all items from the main cache and from every subsession cache as well.</t>

</section>
<section anchor="notify"><name>notify: Notify the User of Additional Steps</name>

<figure><artwork><![CDATA[
opac notify FILENAME MESSAGE
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: NOTIFICATION_HANDLE</t>
</list></t>

<t>This invocation causes <spanx style="verb">opac</spanx> to emit a non-interactive notification to the user.</t>

<t>This is intended specifically for the case where the user needs to take an action for the OpenPGP operation to succeed that the application cannot trigger on the user's behalf.
For example, if the implementation needs the user to press a button on a USB hardware token to permit the use of secret key material, it might use <spanx style="verb">opac notify</spanx> so that the user knows that the application is awaiting action from them.</t>

<t>If <spanx style="verb">MESSAGE</spanx> is malformed (see <xref target="message"/>), it fails with <spanx style="verb">MESSAGE_MALFORMED</spanx>, and emits nothing on standard output.</t>

<t>If it was unable to produce a notification, it fails with <spanx style="verb">COULD_NOT_NOTIFY</spanx>, and emits nothing on standard output.</t>

<t>If it successfully notifies the user, it emits a <spanx style="verb">NOTIFICATION_HANDLE</spanx> (see <xref target="notification-handle"/>) on standard output.
This <spanx style="verb">NOTIFICATION_HANDLE</spanx> can be used to dismiss the notification (see <xref target="dismiss"/>) if the application determines it is no longer needed (for example, when the button has been pressed, and the USB hardware token returned a response).</t>

<t><spanx style="verb">opac notify</spanx> ignores the cache, and uses no configuration variables, so it ignores <spanx style="verb">OPAC_SUBSESSION</spanx>.</t>

</section>
<section anchor="dismiss"><name>dismiss: Dismiss a Notification</name>

<figure><artwork><![CDATA[
opac dismiss NOTIFICATION_HANDLE
]]></artwork></figure>

<t><list style="symbols">
  <t>Standard Input: ignored</t>
  <t>Standard Output: nothing</t>
</list></t>

<t>This invocation is used solely to dismiss a notification that had been created with <spanx style="verb">opac notify</spanx> (see <xref target="notify"/>).</t>

<t>The only additional argument is a <spanx style="verb">NOTIFICATION_HANDLE</spanx> (see <xref target="notification-handle"/>), which should match a value emitted from <spanx style="verb">opac notify</spanx> (see <xref target="notify"/>).</t>

<t>It always succeeds, even if the <spanx style="verb">NOTIFICATION_HANDLE</spanx> could not be dismissed.</t>

<t><spanx style="verb">opac dismiss</spanx> ignores the cache, and uses no configuration variables, so it ignores <spanx style="verb">OPAC_SUBSESSION</spanx>.</t>

</section>
</section>
<section anchor="error-codes"><name>Error Codes</name>

<t><spanx style="verb">opac</spanx>, like any other process, returns an error code.
The following values are defined for specific errors.</t>

<texttable title="Return Codes for opac" anchor="return-codes">
      <ttcol align='left'>Value</ttcol>
      <ttcol align='left'>Name</ttcol>
      <ttcol align='left'>Description</ttcol>
      <c>0</c>
      <c><spanx style="verb">SUCCESS</spanx></c>
      <c>Success</c>
      <c>1</c>
      <c><spanx style="verb">UNSUPPORTED_SUBCOMMAND</spanx></c>
      <c>Unsupported subcommand</c>
      <c>2</c>
      <c><spanx style="verb">UNSUPPORTED_OPTION</spanx></c>
      <c>Unsupported option</c>
      <c>3</c>
      <c><spanx style="verb">MALFORMED_MESSAGE</spanx></c>
      <c>Message is malformed</c>
      <c>4</c>
      <c><spanx style="verb">USER_DECLINED</spanx></c>
      <c>User declined to provide a password or permit use of the cache</c>
      <c>5</c>
      <c><spanx style="verb">PROMPT_TIMED_OUT</spanx></c>
      <c>User failed to take action in response to a prompt</c>
      <c>6</c>
      <c><spanx style="verb">CACHE_DECLINED</spanx></c>
      <c>Cache entry was not added</c>
      <c>7</c>
      <c><spanx style="verb">INVALID_FILENAME</spanx></c>
      <c>An inappropriate filename was requested for caching</c>
      <c>8</c>
      <c><spanx style="verb">COULD_NOT_REMOVE_FROM_CACHE</spanx></c>
      <c>An entry remains in the cache that should have been dropped</c>
      <c>9</c>
      <c><spanx style="verb">NO_ASSOCIATED_VALUE</spanx></c>
      <c>A request was made to drop a password or internal cache entry that did not exist</c>
      <c>10</c>
      <c><spanx style="verb">INVALID_CONFIGURATION_FILE</spanx></c>
      <c>The config file was not well-formed</c>
      <c>11</c>
      <c><spanx style="verb">MALFORMED_PASSWORD</spanx></c>
      <c>Password format is not supported</c>
      <c>12</c>
      <c><spanx style="verb">MALFORMED_INTERNAL_LABEL</spanx></c>
      <c>The Internal contextual label was malformed</c>
      <c>13</c>
      <c><spanx style="verb">MALFORMED_INTERNAL_VALUE</spanx></c>
      <c>The Internal value was too short</c>
      <c>14</c>
      <c><spanx style="verb">INCOMPATIBLE_OPTIONS</spanx></c>
      <c>The command line options and environment variables supplied are mutually incompatible</c>
      <c>15</c>
      <c><spanx style="verb">COULD_NOT_NOTIFY</spanx></c>
      <c>A notification was requested, but could not be produced</c>
      <c>16</c>
      <c><spanx style="verb">MALFORMED_SUBSESSION_ID</spanx></c>
      <c>A malformed subsession identifier was supplied</c>
</texttable>

</section>
<section anchor="configuration"><name>Configuration</name>

<t><spanx style="verb">opac</spanx> should behave sensibly without any configuration file, or with an empty configuration file.</t>

<t>It always looks for its configuration as an "inifile" in exactly one location:</t>

<t><list style="symbols">
  <t>If <spanx style="verb">$OPAC_SUBSESSION</spanx> is set to a non-empty string, and <spanx style="verb">$OPAC_SUBSESSION_CONFIG</spanx> is set, it looks for the file in <spanx style="verb">$OPAC_SUBSESSION_CONFIG</spanx>.
FIXME: if <spanx style="verb">$OPAC_SUBSESSION_CONFIG</spanx> is unset, should it really fall through to reading the main session config?</t>
  <t>Otherwise, if <spanx style="verb">$XDG_CONFIG_HOME</spanx> is set, it looks in <spanx style="verb">$XDG_CONFIG_HOME/opac/config</spanx></t>
  <t>Otherwise, it looks in <spanx style="verb">~/.config/opac/config</spanx></t>
</list></t>

<t><spanx style="verb">opac</spanx> does not attempt to coalesce multiple configuration files.</t>

<section anchor="configuration-example"><name>Configuration Example</name>

<figure><sourcecode type="text/plain" name="~/.config/opac/config"><![CDATA[
[opac]
cache_duration=10s

[opac "~/.private/bob.key"]
on_reuse=confirm
]]></sourcecode></figure>

</section>
<section anchor="configuration-file-format"><name>Configuration File Format</name>

<t>The OPAC configuration file is an "inifile".</t>

<t>It has one optional base section, simply named <spanx style="verb">opac</spanx>, which contains configuration values that supersede the built-in defaults, and take effect when no override is present.</t>

<t>It has any number of file-specific subsections, which contain configuration overrides for specific objects in the filesystem.
A file-specific subsection (within <spanx style="verb">opac</spanx>) is named with a representation of a path in the filesystem.
The path <bcp14>MUST</bcp14> start with either <spanx style="verb">/</spanx> (indicating an absolute path to a file) or <spanx style="verb">~/</spanx> (indicating a filename relative to the user's home directory).</t>

<t><spanx style="verb">opac</spanx> <bcp14>MUST</bcp14> ignore any unexpected or unknown sections or values.
If <spanx style="verb">opac</spanx> ever updates its own configuration, it <bcp14>MUST NOT</bcp14> alter any unexpected or unknown sections or values, reorder sections, or modify comments.</t>

<t>When looking up a configuration option for a prompt or a cache for a password or internal value associated with <spanx style="verb">FILENAME</spanx>, <spanx style="verb">opac</spanx> looks up such a key in the following places:</t>

<t><list style="numbers" type="1">
  <t>In the <spanx style="verb">[opac "FILENAME"]</spanx> subsection of the config file</t>
  <t>In <spanx style="verb">[opac]</spanx> section of the config file</t>
  <t>In the application's built-in settings</t>
</list></t>

<t>Each configuration option is looked up separately, so in the example above, when using <spanx style="verb">~/.private/bob.key</spanx>, <spanx style="verb">on_reuse</spanx> is set to <spanx style="verb">confirm</spanx> and <spanx style="verb">cache_duration</spanx> is set to <spanx style="verb">10s</spanx>.</t>

</section>
<section anchor="what-are-the-configuration-values"><name>What are the configuration values?</name>

<t>There are three configuration directives available.</t>

<section anchor="config-cache-duration"><name>cache_duration: Time to Cache</name>

<t>The <spanx style="verb">cache_duration</spanx> directive accepts a <spanx style="verb">CACHE_DURATION</spanx> value (see <xref target="cache-duration"/>).</t>

<t>A reasonable default value for <spanx style="verb">cache_duration</spanx> is <spanx style="verb">1h</spanx>.</t>

</section>
<section anchor="config-prompt-timeout"><name>prompt_timeout: Time to Wait For User Feedback</name>

<t>The <spanx style="verb">prompt_timeout</spanx> directive accepts a <spanx style="verb">PROMPT_TIMEOUT</spanx> value (see <xref target="prompt-timeout"/>).</t>

<t>A reasonable default value for <spanx style="verb">prompt_timeout</spanx> is <spanx style="verb">1m</spanx>.</t>

</section>
<section anchor="config-on-reuse"><name>on_reuse: Action on Cache Retrieval</name>

<t>The <spanx style="verb">on_reuse</spanx> directive accepts a <spanx style="verb">REUSE_DIRECTIVE</spanx> value (see <xref target="reuse-directive"/>).</t>

<t>A reasonable default value for <spanx style="verb">on_reuse</spanx> is <spanx style="verb">notify</spanx>.</t>

</section>
</section>
</section>
<section anchor="subsessions"><name>Subsessions</name>

<t>OPAC is typically used directly in association with the user's session.
However, it also supports the idea of a "subsession", to support an isolated cache for the use cases of test suites (see <xref target="use-case-test-suite"/>) or isolated applications (see <xref target="use-case-isolated-app"/>).</t>

<t>A subsession shares the same prompting mechanism as the main session, but uses a completely distinct cache and configuration.</t>

<t><spanx style="verb">opac</spanx> knows to use a subsession when the environment variable <spanx style="verb">OPAC_SUBSESSION</spanx> is set to a non-empty string.
The value of <spanx style="verb">OPAC_SUBSESSION</spanx> is the subsession identifier.</t>

<section anchor="subsession-identifiers"><name>Subsession Identifiers</name>

<t>The subsession is identified by an ASCII string consisting of printable (non-whitespace) characters.
The subsession identifier must be at least one octet long, and no more than 64 octets.</t>

<t>If <spanx style="verb">opac</spanx> is using the cache, and <spanx style="verb">OPAC_SUBSESSION</spanx> is non-empty and it is not conformant to this specification, <spanx style="verb">opac</spanx> fails with <spanx style="verb">MALFORMED_SUBSESSION_ID</spanx>.</t>

</section>
<section anchor="subsession-configuration"><name>Subsession Configuration</name>

<t>When using a subsession (that is, when <spanx style="verb">OPAC_SUBSESSION</spanx> is set), if the environment variable <spanx style="verb">OPAC_SUBSESSION_CONFIG</spanx> is set, <spanx style="verb">opac</spanx> reads its the configuration file from the location named in <spanx style="verb">OPAC_SUBSESSION_CONFIG</spanx>.</t>

</section>
</section>
<section anchor="data-types"><name>Data Types</name>

<section anchor="prompt-timeout"><name>PROMPT_TIMEOUT</name>

<t>This represents a length of time that a prompt should be displayed to the user before it is dismissed as having been ignored.</t>

<t>It is represented in an integer number of hours, minutes, and seconds, using letter suffixes.
Hours, if present, come first and are suffixed with <spanx style="verb">h</spanx>.
Minutes, if present, appear in the middle, and are suffixed with <spanx style="verb">m</spanx>.
Seconds, if present, appear at the end, and are suffixed with <spanx style="verb">s</spanx>.</t>

<t>If no letter suffix is present, a completely numeric value is read as seconds.</t>

<t>For example, <spanx style="verb">1m30s</spanx> means the same timeout as <spanx style="verb">90</spanx>, and <spanx style="verb">1h2s</spanx> means the same timeout as <spanx style="verb">3602</spanx></t>

<t>Using the value <spanx style="verb">0</spanx> means that where prompting is necessary, <spanx style="verb">opac</spanx> <bcp14>MUST NOT</bcp14> prompt, but should instead immediately fail with <spanx style="verb">PROMPT_TIMED_OUT</spanx>.</t>

<t>Using the special value <spanx style="verb">never</spanx> means to never deliberately time out the prompt.
An OPAC implementation may nevertheless fail with <spanx style="verb">PROMPT_TIMED_OUT</spanx> due to other compelling circumstances.
For example, if the prompt is a confirmation prompt for the reuse of a cached value, and that cached value is removed from the cache, or if the user's session is ending and the OPAC implementation is trying to clean up, it <bcp14>MAY</bcp14> fail with <spanx style="verb">PROMPT_TIMED_OUT</spanx>.</t>

</section>
<section anchor="cache-duration"><name>CACHE_DURATION</name>

<t>This represents the maximum amount of time that a value will persist in its position in the cache.</t>

<t>It is represented in an integer number of days, hours, minutes, and seconds, using letter suffixes.
Days, if present, come first and are suffixed with <spanx style="verb">d</spanx>.
Hours, if present, follow days and are suffixed with <spanx style="verb">h</spanx>.
Minutes, if present, follow hours, and are suffixed with <spanx style="verb">m</spanx>.
Seconds, if present, appear at the end, and are suffixed with <spanx style="verb">s</spanx>.</t>

<t>If no letter suffix is present, a completely numeric value is read as seconds.</t>

<t>For example, <spanx style="verb">1m30s</spanx> means the same timeout as <spanx style="verb">90</spanx>, and <spanx style="verb">1h2s</spanx> means the same timeout as <spanx style="verb">3602</spanx></t>

<t>Using the special value <spanx style="verb">never</spanx> is the same as <spanx style="verb">0</spanx>, meaning that OPAC should never cache this value.
(This is particularly useful in the configuration file; from the command line, the easier thing would be to simply never ask for caching in the first place)</t>

<t>This value may be supplied from the command line during cache insertion (see <xref target="cache-password"/> and <xref target="cache-internal"/>) and from the configuration file (see <xref target="config-cache-duration"/>).
If it is specified in both the command line and the configuration file, the shorter of the two values provided is preferred.</t>

</section>
<section anchor="reuse-directive"><name>REUSE_DIRECTIVE</name>

<t>This form describes what an OPAC implementation should do when a value is elicited from the cache, and the cache can supply the value.</t>

<t>It can be one of three possible values, in increasing order of strictness: <spanx style="verb">ok</spanx>, <spanx style="verb">notify</spanx>, or <spanx style="verb">confirm</spanx>.</t>

<t><spanx style="verb">ok</spanx> permits the use of the cached value without any interaction with the user.</t>

<t><spanx style="verb">notify</spanx> emits a standard notification while permitting the use of the cached value.</t>

<t><spanx style="verb">confirm</spanx> asks the user to confirm the use of the cached value.
In this case, the user may decline its use.</t>

<t>This value may be supplied from the command line during cache insertion (see <xref target="cache-password"/> and <xref target="cache-internal"/>) and from the configuration file (see <xref target="config-on-reuse"/>).
If it is specified in both the command line and the configuration file, the stricter of the two values provided is preferred.
For example, if the configuration file indicates that a given value can be replayed from the cache as long as the user is notified (<spanx style="verb">notify</spanx>), then a command-line option of <spanx style="verb">--on-reuse=confirm</spanx> will ask the user to confirm the use, but a command-line option of <spanx style="verb">--on-reuse=ok</spanx> will not suppress the notification.</t>

</section>
<section anchor="notification-handle"><name>NOTIFICATION_HANDLE</name>

<t>This is a unique string that can be used to dismiss a previous notification when that notification is no longer relevant.
It is produced by <spanx style="verb">opac notify</spanx> (see <xref target="notify"/>) and can be used to dismiss a specific notification with <spanx style="verb">opac dismiss</spanx> (see <xref target="dismiss"/>).
It consists only of printable ASCII characters (no whitespace), and will be no more than 64 characters in length.</t>

</section>
<section anchor="internal-label"><name>INTERNAL_LABEL</name>

<t>This is a label used by an OpenPGP implementation to associate the output of a specific cryptographic process associated with a file.
It is implementation-specific, but must be a UTF-8 encoded string of no more than 128 octets in length.
It is used, with the filename itself, as an index into the OPAC cache in <spanx style="verb">opac cache-internal</spanx> (see <xref target="cache-internal"/>) and <spanx style="verb">opac get-internal</spanx> (see <xref target="get-internal"/>).</t>

<t>As a simple example, an OpenPGP implementation might choose to base64-encode the S2K Usage Octet and the accompanying parameters from a Secret Key Packet, and then prefix that with a short identifying label.</t>

</section>
<section anchor="internal-value"><name>INTERNAL_VALUE</name>

<t>An internal value is simply a non-empty octet string of no more than 1000 octets.</t>

<t>Beyond the length limits, there are no constraints on its content.</t>

</section>
<section anchor="message"><name>MESSAGE</name>

<t>This is a limited textual string that is presented to the user when the user is prompted or notified.
It is a way for an application requesting data from the user to provide some additional context for what is being requested or why it is being requested.</t>

<t>It <bcp14>MUST</bcp14> be UTF-8-encoded, no more than 120 characters, with no more than two internal LINE FEED (U+000A) characters.
Leading and trailing whitespace will be ignored.</t>

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

<t>OPAC expects a password to be a UTF-8-encoded, non-empty string.
The password <bcp14>MUST NOT</bcp14> contain any LINE FEED (U+000A) characters, and leading or trailing whitespace may be stripped.
A password <bcp14>MUST NOT</bcp14> be more than 1000 octets in length in its UTF-8 form.
If a password is supplied that cannot be brought into conformance with these specifications, <spanx style="verb">opac</spanx> will fail with <spanx style="verb">MALFORMED_PASSWORD</spanx>.</t>

<t>The OpenPGP standard permits the use of a password as an arbitrary bytestream, so it is possible that some OpenPGP material may be encrypted with a password that does not conform to these constraints.
It is recommended to use an OpenPGP tool that does not use OPAC change to such a password to a conformant string.</t>

</section>
</section>
<section anchor="subtleties-and-nuance"><name>Subtleties and Nuance</name>

<t>The design of OPAC is intended to make normal, straightforward use cases easy and simple.
It cannot handle all possible scenarios.</t>

<t>This section describes some details about the underlying assumptions in its design, including some descriptions of scenarios where it will not work as expected.</t>

<section anchor="the-opac-cache"><name>The OPAC Cache</name>

<t>The OPAC main cache is structured as a two-level nested tree.
The top level index is by filename.
Each filename can have zero or one <spanx style="verb">PASSWORD</spanx>s (see <xref target="password"/>) associated with it.
Additionally, each filename can have zero or more <spanx style="verb">INTERNAL_LABEL</spanx>s (see <xref target="internal-label"/>) associated with it.
If the (filename, <spanx style="verb">INTERNAL_LABEL</spanx>) tuple exists, it has an <spanx style="verb">INTERNAL_VALUE</spanx> associated with it.</t>

<t>Here is an example populated cache showing the indexing and the types of stored values:</t>

<figure><artwork><![CDATA[
├┬╴/tmp/secret-message.pgp
│└─╴"BarPGP:23e1b0a7cbe322bf5c096cb3d1bc" → INTERNAL_VALUE
├─╴/home/bob/src/mysoft/distribution.key → PASSWORD
└┬╴/home/bob/.private/bob.key → PASSWORD
 ├─╴"FooPGP:YXdsO2loeXFhaXdlZ2xhd2Vwa2Ewd2l0MjI" → INTERNAL_VALUE
 └─╴"FooPGP:Z3E0Mzl2bTtqOWZvd2x3" → INTERNAL_VALUE
]]></artwork></figure>

<t>Some observations about this example:</t>

<t><list style="symbols">
  <t>No password was cached for <spanx style="verb">/tmp/secret-message.pgp</spanx>, but an internal value was cached, probably by the BarPGP implementation.</t>
  <t>Only a password was cached for the <spanx style="verb">distribution.key</spanx>.</t>
  <t><spanx style="verb">bob.key</spanx> has cached a password and multiple internal values.
One internal value might correspond to the output of some stage of the S2K process for unlocking the primary key, while the other might be for unlocking a subkey.</t>
  <t>The choice of the <spanx style="verb">INTERNAL_LABEL</spanx>s present in the cache are arbitrary and up to the implementations.
In this example, <spanx style="verb">FooPGP</spanx> and <spanx style="verb">BarPGP</spanx> have used a namespacing approach within labels to ensure that they don't accidentally collide with each other's labels.</t>
</list></t>

<t>The cache depends on a view of the filesystem that aligns with the view seen by the process invoking <spanx style="verb">opac</spanx>.</t>

<section anchor="cache-lifecycle"><name>Cache Lifecycle</name>

<t>When the user's sessions starts, the OPAC cache is empty.</t>

<t>As elements are added to the cache, they should be marked clearly with expected expiration times, and removed (any associated memory wiped if possible) promptly when the stored password or internal value expires from the cache.</t>

<t>FIXME: configuration might change between insertion and retrieval from the cache; if they differ, which one should take precedence at retrieval time?</t>

</section>
<section anchor="subsession-cache-structure"><name>Subsession Cache Structure</name>

<t>Each subsession, identified by a subsession ID, has an independent cache that is shaped just like the main cache.</t>

<t>If OPAC gets a cache retrieval request for a previously unknown subsession ID, it treats it as a cache miss.
If OPAC gets a cache insertion request for a previously unknown subsession ID, it initializes a new, empty cache for the subsession, and inserts the password or internal value in the new cache.</t>

<t>When a cache insertion or retrieval is performed under a subsession, it works only with that subsession cache, and does not look in the main cache.
When an insertion or retrieval is done outside of a subsession, it only uses the main cache, and does not look in any subsession cache.</t>

<t>See also <xref target="subsession-nuance"/> for more about subsessions.</t>

</section>
<section anchor="cache-insertion-vs-cache-retrieval"><name>Cache Insertion vs. Cache Retrieval</name>

<t>Note that the <spanx style="verb">opac</spanx> interface completely separates cache insertion from cache retrieval.</t>

<t>In particular, <spanx style="verb">opac get-password</spanx> retrieves a password from the cache or from the user, but does not insert a user-provided password in the cache.
This is because <spanx style="verb">opac</spanx> is not expected to directly interact with the OpenPGP objects, so it cannot know whether the user's supplied password works or not.</t>

</section>
</section>
<section anchor="opac-prompting"><name>OPAC Prompting</name>

<t>OPAC supports three types of user interaction, collectively known as "prompting".</t>

<t><list style="symbols">
  <t>Notification -- this might happen during cache retrieval, depending on the configuration, or explicitly via <spanx style="verb">opac notify</spanx>.</t>
  <t>Confirmation (boolean approval) -- this might happen during cache retrieval, depending on the configuration.</t>
  <t>Elicit a string of text -- this might happen during <spanx style="verb">opac get-password</spanx>, if the requested password is not found in the cache.</t>
</list></t>

<t>Additionally, a user of OPAC may dismiss a prior notification (when it is no longer relevant) -- but only notifications from <spanx style="verb">opac notify</spanx> can be dismissed in this way.</t>

<t>Each of these forms of prompting <bcp14>MAY</bcp14> be accompanied by an application-supplied <spanx style="verb">MESSAGE</spanx>, which will be clearly delimited from any OPAC-specific metadata, such as the path to the associated file, or any information about the caller of <spanx style="verb">opac</spanx>.</t>

</section>
<section anchor="subsession-nuance"><name>OPAC Subsessions</name>

<t>OPAC needs subsessions because there are circumstances where the desired scope of an OpenPGP unlocking step isn't contiguous with the user's interactive session as a whole.</t>

<t>In particular, a software test suite is likely to want to lock and unlock various OpenPGP objects independently of the rest of the session (see <xref target="use-case-test-suite"/>).
And an application that spans multiple processes want to lock and unlock various OpenPGP objects without interference from the rest of the session (see <xref target="use-case-isolated-app"/>).</t>

<section anchor="subsession-configuration-1"><name>Subsession Configuration</name>

<t>Note that the user's configuration values can't necessarily override subsession configuration, because subsession config might come from somewhere else, via the <spanx style="verb">OPAC_SUBSESSION_CONFIG</spanx> environment variable.</t>

<t>The two main use cases for subsessions are test suites and isolated apps.
A test suite wants to use its own dedicated configuration, and for reproducibility it shouldn't be influenced by configuration that happens to live outside its own workspace, even if run within the user's session.</t>

<t>Similarly, an isolated app might want the user to be able to configure how the app handles OpenPGP prompting and caching, but without asking the user to manage some system-wide configuration.</t>

</section>
</section>
<section anchor="passwords-vs-internal-values"><name>Passwords vs. Internal Values</name>

<t>OPAC handles both passwords and internal values.
Note the differences between  how it handles each of these things:</t>

<t><list style="symbols">
  <t>passwords are human-readable UTF-8 strings, internal values are octet strings.</t>
  <t>one password per <spanx style="verb">FILENAME</spanx> (in the main cache)</t>
  <t>arbitrary numbers of internal values per <spanx style="verb">FILENAME</spanx></t>
  <t>nonetheless, they are all bound together at the <spanx style="verb">FILENAME</spanx> level for things like configuration and <spanx style="verb">drop-cache</spanx>.</t>
</list></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>




    </references>

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

<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="I-D.dkg-openpgp-stateless-cli">
   <front>
      <title>Stateless OpenPGP Command Line Interface</title>
      <author fullname="Daniel Kahn Gillmor" initials="D. K." surname="Gillmor">
         <organization>American Civil Liberties Union</organization>
      </author>
      <date day="1" month="March" year="2024"/>
      <abstract>
	 <t>   This document defines a generic stateless command-line interface for
   dealing with OpenPGP messages, known as sop.  It aims for a minimal,
   well-structured API covering OpenPGP object security.

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-dkg-openpgp-stateless-cli-10"/>
   
</reference>


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

	 </t>
      </abstract>
   </front>
   <seriesInfo name="Internet-Draft" value="draft-dkg-openpgp-external-secrets-01"/>
   
</reference>




    </references>


<?line 657?>

<section anchor="example-uses"><name>Example Uses</name>

<t><spanx style="verb">opac</spanx> offers a minimal interface that can be used for a variety of common use cases.
This section provides a few simple motivational examples of how it can be integrated to support these cases.</t>

<t>These examples are not necessarily complete, but should give a flavor of the supported scenarios.</t>

<section anchor="integration-with-the-stateless-openpgp-command-line-interface-sop"><name>Integration with the Stateless OpenPGP Command-Line Interface (SOP)</name>

<t>It should be easy to integrate OPAC into SOP, the Stateless OpenPGP command-line interface described in <xref target="I-D.dkg-openpgp-stateless-cli"/>.
The integration can make use of prompting on its own, or it may also make use of the caching capabilities for a more usable, session-oriented approach.</t>

<section anchor="opac-sop-prompting"><name>OPAC + SOP: Prompting</name>

<t>Using POSIX-compliant shell, an OpenPGP application can combine <spanx style="verb">opac</spanx> and <spanx style="verb">sop</spanx> to decrypt a message with a locked Secret Key like this:</t>

<figure><artwork><![CDATA[
BOBPW=$(opac get-password bob.key) \
  sop decrypt --with-key-password @ENV:BOBPW bob.key < msg.txt
]]></artwork></figure>

<t>Alternately, using slightly fancier shells like <spanx style="verb">bash</spanx> or <spanx style="verb">zsh</spanx> that offer command substitution:</t>

<figure><artwork><![CDATA[
sop decrypt --with-key-password <(opac get-password bob.key) \
    bob.key < msg.txt
]]></artwork></figure>

<t>Other similar combinations (such as file descriptor redirection) should be straightforward from a wide range of programming environments.</t>

</section>
<section anchor="opac-sop-prompting-and-caching"><name>OPAC + SOP: Prompting and Caching</name>

<t>If the OpenPGP application also wants to make use of <spanx style="verb">opac</spanx>'s cache, it can do something like the following POSIX shell:</t>

<figure><artwork><![CDATA[
# from SOP's standard return codes:
KEY_IS_PROTECTED=67

BOBPW=$(opac get-password bob.key)
PASS=$BOBPW sop decrypt --with-key-password @ENV:PASS \
                bob.key < msg.txt > msg.decrypted;
SOP_RESULT=$?
if [ 0 -eq $SOP_RESULT ]; then
    printf '%s' "$PASS" | opac cache-password bob.key
elif [ $KEY_IS_PROTECTED -eq $SOP_RESULT ]; then
    opac drop-cache bob.key
fi
]]></artwork></figure>

<t>This process shows the use of the password cache: when a secret is successfully unlocked, the password is retained in the cache; if it does not work, the cache for that object is deliberately cleared so that the user would be prompted in the future.</t>

</section>
</section>
<section anchor="use-case-test-suite"><name>Test Suite Isolation</name>

<t>A test suite that includes locked OpenPGP material typically wants to run code that would normally interact directly with the user, but should not require actual user interaction.
Furthermore, a test suite typically does not want to interact with the caching or prompting of the interactive session of the developer running the test suite.</t>

<t>OPAC aims to support this use case with subsessions (see <xref target="subsessions"/>).
An OPAC subsession is identified with a unique string, and a subsession indicated to <spanx style="verb">opac</spanx> through an environment variable.</t>

<t>Here is a comprehensive example in POSIX shell, wrapping a test suite so that it uses an OPAC subsession with a randomly-derived subsession identifier.
It uses a dedicated configuration file to discourage prompting, and to cache everything for the entire session.
It pre-emptively seeds the password cache with the password for the locked key.
After the test suite is run, it cleans up after itself.</t>

<figure><artwork><![CDATA[
export OPAC_SUBSESSION=$(head -c12 < /dev/urandom | base64)
cat > opac.config <<EOF
[opac]
cache_duration=session
prompt_timeout=0
EOF
export OPAC_SUBSESSION_CONFIG=$(pwd)/opac.config
printf correct horse battery staple | opac cache-password ./bob.key

# ... run test suite that uses the locked bob.key...

opac drop-cache
unset -v OPAC_SUBSESSION OPAC_SUBSESSION_CONFIG
]]></artwork></figure>

</section>
<section anchor="use-case-isolated-app"><name>Single-Application Subsession Use</name>

<t>An OPAC subsession can also be used by a single application, to isolate its prompting and caching state from other applications also running in the session.</t>

<t>For example, an application might be split across multiple processes, and each process should be able to use the same shared cache as the other processes in the application.
But the application might not want its own OpenPGP material to be available for other applications running in the same user session.</t>

<t>An application in this situation might set up an OPAC subsession upon application start, exporting it to all child processes.
The two examples in this subsection are in Python-like pseudocode.</t>

<figure><artwork><![CDATA[
def app_init():
    ...
    if use_subsession:
        opac_subsession = base64(get_random(12))
        subprocess_environment["OPAC_SUBSESSION"] = opac_subsession
    ...
]]></artwork></figure>

<t>And on application shutdown, it could flush the cache:</t>

<figure><artwork><![CDATA[
def app_cleanup():
    ...
    if "OPAC_SUBSESSION" in subprocess_environemnt:
       subprocess("opac", "drop-cache")
    ...
]]></artwork></figure>

</section>
<section anchor="openpgp-internal-use"><name>OpenPGP Internal Use</name>

<t>An application that uses OpenPGP in a more fine-grained way than just interacting with a SOP instance might also want to cache some intermediate/internal values to free up resources in future processing.</t>

<t>For example, if an S2K operation takes a gigabyte of RAM and 3 seconds on the current processor, the application might want to cache the result of the S2K operation, rather than just caching the password.</t>

<t>The application can use OPAC for this kind of caching as well, but it uses a different interface than the password interface, because the user is never prompted to supply the value itself.
Depending on the configuration, the user may be prompted to confirm the use of the value, though.</t>

<t>In Pythonic pseudocode, that might look something like:</t>

<figure><artwork><![CDATA[
def unlock_key(key, explanation):
    label = get_internal_label(key)
    value = subprocess("opac", "get-internal",
                       "--message", explanation,
                       key.filename, label)
    if value is None:
        password = subprocess("opac", "get-password",
                              "--message", explanation,
                              key.filename).get_stdout()
        value = OpenPGP_string_to_key(key.s2kparams, password)
    if unlock_key_with_intermediate(key, value):
        subprocess("opac", "cache-internal",
                   key.filename, label).write_stdin(value)
    else:
        subprocess("opac", "drop-cache", key.filename)
]]></artwork></figure>

</section>
<section anchor="notifying-the-user-of-external-requirements"><name>Notifying the User of External Requirements</name>

<t>In some cases, an OpenPGP-using application might need access to external secret key material, like a smartcard, USB hardware token, or some other device (see <xref target="I-D.dkg-openpgp-external-secrets"/>).
In such a case, the application may need to notify the user that they need to take some additional action, like pressing a button on a USB device, or scanning their fingerprint.</t>

<t>When the application is aware of this need, it might want to send the user a generic notification.
Once the user presses the button, the application might want to dismiss the notification.
In Pythonic pseudocode, that might look like:</t>

<figure><artwork><![CDATA[
def handle_external_key():
    handle = subprocess("opac", "notify", "--message",
                        "Please press the USB button")
    ... # wait on external mechadimfor operation to complete
    subprocess("opac", "notify", "--clear", handle)
]]></artwork></figure>

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

<t>This document describes a command-line interface, as that is a widely interoperable interface that anyone can implement.</t>

<t>It might be useful to describe more nuanced, alternate interfaces that would be easier to work with for some implementations, like a C library API, or even a D-Bus interface for those platforms that use D-Bus.</t>

<t>One of the tricks for this is that the interface -- in particular <spanx style="verb">opac get-password</spanx> or <spanx style="verb">opac-get-internal-value</spanx> -- can be quite high-latency, particularly when awaiting a response from the user.
This probably means that a more nuanced interfce will require some kind of asynchronous interface functionality to avoid blocking the main application.</t>

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

<t>Much appreciation to the people who gave feedback on this document, including
Jameson Rollins and
Heiko Schäfer.</t>

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

<section anchor="draft-dkg-openpgp-prompting-caching-00"><name>draft-dkg-openpgp-prompting-caching-00</name>

<t>Initial sketch of the interface.</t>

</section>
</section>


  </back>

<!-- ##markdown-source:
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
hm7uxaumAAA=

-->

</rfc>

