# Tor Project SSH protocol extensions

The
[SSH protocol](https://datatracker.ietf.org/doc/html/rfc4251)
provides various extension facilities.

The Tor Project has defined some extensions,
using the
[domain-name-based extension facility](https://datatracker.ietf.org/doc/html/rfc4250#section-4.6.1).
The Tor Project uses names ending `@spec.torproject.org`.

| Id(s)       | Namespace  | Summary  |  Specification<br>link (retrieved at)  |
|----------|--------------|----------|-------------------------------------|
| **`ed25519-expaneded@`**  | [Public key algorithm](https://datatracker.ietf.org/doc/html/rfc4250#section-4.11.3) (in SSH/OpenSSH key file) | Expanded ed25519 private key  | [Arti keystore types]
| **`x25519@`**   | [Public key algorithm](https://datatracker.ietf.org/doc/html/rfc4250#section-4.11.3) (in SSH/OpenSSH key file) | X25519 keys  | [Arti keystore types] |

## Registration process

New entries may be added to this table
after peer review by the Tor Project developers,
via
[gitlab](https://gitlab.torproject.org/tpo/core/torspec)
merge request.

The specification links may be to external documents,
not managed as part of the Tor Specifications.
Or, they may be links to specific sections of the Tor Specifications,
or to Proposals.
External links should be dated, for ease of future reference.

Ideally, before a protocol is deployed,
its specification should be transferred to the Tor Specifications
(and the link in the table adjusted).

## Interpretation

This section uses
the notation and conventions from
[`PROTOCOL.key`](https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD))
and
SSH including [RFC4251 s5](https://datatracker.ietf.org/doc/html/rfc4251#section-5)),
not those from the rest of the Tor Specifications.

### Interpreting the table

For example, the row for `x25519@` indicates that:

 * The Tor Project has assigned `x25519@spec.torproject.org`
 * In the namespace of public key algorithms -
   see [RFC4250 table 4.11.3](https://datatracker.ietf.org/doc/html/rfc4250#section-4.11.3),
   but only when found within an SSH/OpenSSH format key file.
 * The meaning of this name is summarised as "X25519 private key"
 * The full details can be found at the linked text,
   which is part of the Arti keystore section, below.

The registered names resemble email addresses,
but they are **not email addresses**
and mail to them will not be delivered.

For further information, consult the linked specifications.

## SSH key types for the Arti keystore

[Arti keystore types]: #ssh-key-types-for-the-arti-keystore

The
[Arti keystore](https://tpo.pages.torproject.net/core/doc/rust/tor_keymgr/index.html)
stores private keys
in OpenSSH key format
(and, sometimes, public keys, in SSH format).
But it needs to store some key types that are
not used in the SSH protocols.
So the following key types are defined.

These are in the namespace of Public Key Algorithms
([RFC4250 4.11.3](https://datatracker.ietf.org/doc/html/rfc4250#section-4.11.3))
but they are only meaningful in
OpenSSH format private key files
([OpenSSH `PROTOCOL.key` document](https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD))
and
SSH public key files
([RFC4716 3.4](https://datatracker.ietf.org/doc/html/rfc4716#section-3.4)).

In each case we specify/reference
 * the name of the "public key algorithm" (RFC4250 4.11.3),
 * the underlying cryptographic algorithm(s),
 * the public key data
   ("key/certificate data" in 
   [RFC4253 6.6](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6)),
   see [Encoding of the public key data](#encoding-of-the-public-key-data)
 * the private key data
   (see [Encoding of the private key data](#encoding-of-the-private-key-data))

### Encoding of the public key data

OpenSSH `PROTOCOL.key` does not clearly state
the contents of the `publickey1`/`publickey2`/`publickeyN` fields
in the outer (unencrypted) section (`PROTOCOL.key` s1),
so we state it here.

Each `publickey` consists of the encoded public key
as per
[RFC4253 6.6](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6)
(under "Certificates and public keys are encoded as follows").

So the overall format of this part of the file is:

```
    uint32        number of keys, N
         string       publickey1, where the contained binary data is:
              string      public key algorithm name (RFC4250 table 4.11.3)
              byte[]      public key data (algorithm-specific)
         ... keys 2 to N-1 inclusive, each as for publickey1 ...
         string       publickeyN (as for publickey1)
```

### Encoding of the private key data

OpenSSH `PROTOCOL.key` defines
the representation of the private key data as, simply:
"using the same rules as used for SSH agent".
However,
no specific section is referred to;
the SSH agent protocol is only available as
an Internet Draft
[draft-miller-ssh-agent-04](https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04);
and, the actual encoding used by OpenSSH is hard to relate
to that document.
So we document our understanding here.

The contents of each `privatekey1`/`privatekey2`/`privatekeyN` is:

```
    string      public key algorithm name (RFC4250 table 4.11.3)
    byte[]      public key data (algorithm-specific)
    byte[]      private key data (algorithm-specific)
```

> Note that this depends on the reader knowing the public key algorithm.
> The public key data must be self-delimiting,
> since the file format doesn't provide a separate length field.
> Although here we discuss only algorithms whose
> public key data, and private key data,
> are each a single `string`, that is not always the case:
> for example,
> the `ssh-rsa` algorithm's key data formats are sequences of `mpint`s
> without any surrounding overall length.
>
> Note also that the encrypted section does not separately state
> the number of keys or their total length.
> The reader must keep reading until it encounters either the end,
> or something that looks like padding (starting with a byte 0x01).

### `x25519@spec.torproject.org`

These refer to keys for
X25519,
ie, Diffie-Hellman on
Curve25519,
as per
[RFC7748 6.1](https://datatracker.ietf.org/doc/html/rfc7748#section-6.1).
and
[s5](https://datatracker.ietf.org/doc/html/rfc7748#section-5).

The public key data is:
```
    string         wrapper for the following fixed-length data:
        byte[32]       the u-coordinate encoded as u[] from RFC7748 s5
```

The private key data is:
```
    string         wrapper for the following fixed-length data:
        byte[32]       the scalar k encoded according to RFC7748 s5
```

k MUST be stored as the true scalar value.
So if the private key was generated from 32 random bytes
according to the procedure described in RFC7748 s5
"in order to decode 32 random bytes as an integer scalar".
the value stored MUST be the "clamped" form:
that is, the value
*after* the transformation.
If a stored value is a byte string which doesn't represent
a valid scalar according to RFC7748 s5
(i.e. an "unclamped" value)
it SHOULD be rejected;
if it is not rejected,
it MUST NOT be used unchanged, but MUST instead be clamped.

Keys whose `string` wrapper is not of the expected length MUST be rejected.

> <span id="useless-string">The
> `string` wrapper is useless,
> but the same wrapper approach is used in official SSH for
> ed25519 public keys ([RFC8709
> s4](https://datatracker.ietf.org/doc/html/rfc8709#name-public-key-format)).
> and for ed25519 private keys in the SSH agent protocol
> ([draft-miller-ssh-agent-04 4.2.3](https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04#section-4.2.3)).
> We do the same here for consistency
> (and implementation convenience).</span>

> X25519 keys are
> [interconvertible with ed25519 keys](dir-spec/converting-to-ed25519.md).
> So, it would be possible to store the ed25519 form instead,
> and convert on load/save.
> However, we use a different key type
> to avoid needing conversions during load/save, and
> to avoid key type punning and accidental key misuse:
> using the same key material for different algorithms is a poor idea.

### `ed25519-expanded@spec.torproject.org`

These refer to the expanded form of private keys for
ed25519
([RFC8032](https://datatracker.ietf.org/doc/html/rfc8032)).

This key type appears within OpenSSH private key files.
When it does, the `ed25519-expanded@spec.torproject.org`
algorithm name is used for
the private key (`PROTOCOL.key` section 3, `privatekey1` etc.)
but also for
the public key (`PROTOCOL.key` section 1, `publickey1` etc.).

> In `PROTOCOL.key` we interpret the requirement that there be
> "matching" public and private keys
> to include the requirement that
> the public key algorithm name strings must be the same.

> In the Arti keystore a private key file
> whose filename ends with `.ed25519_private`
> may contain either
> a standard ed25519 keypair with SSH type `ed25519`
> or
> an `ed25519-expanded@spec.torproject.org` keypair.

`ed25519-expanded@spec.torproject.org`
SHOULD NOT appear in RFC4716 *public* key files.
Software which is aware of this key type
MUST NOT generate such public key files
and SHOULD reject them on loading.
(Software handling keys in a type-agnostic manner
MAY, and probably will, process such files without complaint.)

> These rules are because
> public keys should always be advertised as `ed25519`
> even if the private key is only available as `ed25519-expanded@`:
> this avoids leaking information about the key generation process
> to relying parties,
> and simplifies certification and verification.

> Arti will provide a utility to convert
> anomalous RFC4716 public key files
> containing keys declared to be of type
> `ed25519-expanded@spec.torproject.org`
> to fully conforming files containg `ed25519` keys.
> In other circumstances Arti will reject such anomalous files.

The public key data is the same as for the official `ed25519` type:
```
    string         wrapper for the following fixed-length data:
        byte[32]       the actual public key, ENC(A) from RFC8032 3.2
```
(Reference: [RFC8032 3.2](https://datatracker.ietf.org/doc/html/rfc8032#section-3.2).)

The private key data is as follows:
```
    string         wrapper for the following fixed-length data:
        byte[32]       ENC(s) as per RFC8032 3.2, "expanded secret key"
        byte[32]       `h_b...h_(2b-1)` as per RFC8032 3.3, "separation nonce"
```
(References: `ENC(s)` in [RFC8032 3.2](https://datatracker.ietf.org/doc/html/rfc8032#section-3.2);
`h_b || ... || h_(2b-1)` as per [RFC8032 3.3](https://datatracker.ietf.org/doc/html/rfc8032#section-3.3).)

Keys whose `string` wrapper is not of the expected length MUST be rejected.

> [As with `x25519`, the `string` wrapper is useless](#useless-string).
> We adopt it here for the same reasons.

This private key format does not provide a way to convey or establish
a corresponding (unexpanded, standard) ed25519 private key `k`.

> The ed25519 standards define the private key for ed25519
> as a 32-byte secret `k`.
> `k` is then hashed and processed into parameters used for signing,
> and the public key for verification.
> The `ed25519-expanded@spec.torproject.org` can represent private keys
> which can be used with the ed25519 signature algorithm,
> and for which a corresponding working public key is known,
> but for which there is no known value of `k`
> (the "real ed25519" private key).
> Allowing such keys can be convenient when
> one wishes to find private keys whose public keys have particular patterns,
> for example when trying to find a `.onion` domain
> for a [Tor Hidden Service](rend-spec/).
> This format is also used where 
> [blinded ed25519 keys](rend-spec/keyblinding-scheme.md)
> need to be stored.
