aboutsummaryrefslogtreecommitdiff
path: root/spec/rend-spec/deriving-keys.md
diff options
context:
space:
mode:
Diffstat (limited to 'spec/rend-spec/deriving-keys.md')
-rw-r--r--spec/rend-spec/deriving-keys.md425
1 files changed, 425 insertions, 0 deletions
diff --git a/spec/rend-spec/deriving-keys.md b/spec/rend-spec/deriving-keys.md
new file mode 100644
index 0000000..69eeee6
--- /dev/null
+++ b/spec/rend-spec/deriving-keys.md
@@ -0,0 +1,425 @@
+<a id="rend-spec-v3.txt-2.1"></a>
+
+# Deriving blinded keys and subcredentials {#SUBCRED}
+
+In each time period (see \[TIME-PERIODS\] for a definition of time
+periods), a hidden service host uses a different blinded private key
+to sign its directory information, and clients use a different
+blinded public key as the index for fetching that information.
+
+For a candidate for a key derivation method, see Appendix \[KEYBLIND\].
+
+Additionally, clients and hosts derive a subcredential for each
+period. Knowledge of the subcredential is needed to decrypt hidden
+service descriptors for each period and to authenticate with the
+hidden service host in the introduction process. Unlike the
+credential, it changes each period. Knowing the subcredential, even
+in combination with the blinded private key, does not enable the
+hidden service host to derive the main credential--therefore, it is
+safe to put the subcredential on the hidden service host while
+leaving the hidden service's private key offline.
+
+The subcredential for a period is derived as:
+
+```text
+N_hs_subcred = H("subcredential" | N_hs_cred | blinded-public-key).
+```
+
+In the above formula, credential corresponds to:
+
+```text
+N_hs_cred = H("credential" | public-identity-key)
+```
+
+where `public-identity-key` is the public identity master key of the hidden
+service.
+
+# Locating, uploading, and downloading hidden service descriptors {#HASHRING}
+
+To avoid attacks where a hidden service's descriptor is easily
+targeted for censorship, we store them at different directories over
+time, and use shared random values to prevent those directories from
+being predictable far in advance.
+
+Which Tor servers hosts a hidden service depends on:
+
+```text
+ * the current time period,
+ * the daily subcredential,
+ * the hidden service directories' public keys,
+ * a shared random value that changes in each time period,
+ shared_random_value.
+ * a set of network-wide networkstatus consensus parameters.
+ (Consensus parameters are integer values voted on by authorities
+ and published in the consensus documents, described in
+ dir-spec.txt, section 3.3.)
+
+ Below we explain in more detail.
+```
+
+<a id="rend-spec-v3.txt-2.2.1"></a>
+
+## Dividing time into periods {#TIME-PERIODS}
+
+To prevent a single set of hidden service directory from becoming a
+target by adversaries looking to permanently censor a hidden service,
+hidden service descriptors are uploaded to different locations that
+change over time.
+
+The length of a "time period" is controlled by the consensus
+parameter 'hsdir-interval', and is a number of minutes between 30 and
+14400 (10 days). The default time period length is 1440 (one day).
+
+Time periods start at the Unix epoch (Jan 1, 1970), and are computed by
+taking the number of minutes since the epoch and dividing by the time
+period. However, we want our time periods to start at a regular offset
+from the SRV voting schedule, so we subtract a "rotation time offset"
+of 12 voting periods from the number of minutes since the epoch, before
+dividing by the time period (effectively making "our" epoch start at Jan
+1, 1970 12:00UTC when the voting period is 1 hour.)
+
+Example: If the current time is 2016-04-13 11:15:01 UTC, making the seconds
+since the epoch 1460546101, and the number of minutes since the epoch
+24342435\. We then subtract the "rotation time offset" of 12\*60 minutes from
+the minutes since the epoch, to get 24341715. If the current time period
+length is 1440 minutes, by doing the division we see that we are currently
+in time period number 16903.
+
+Specifically, time period #16903 began 16903\*1440\*60 + (12\*60\*60) seconds
+after the epoch, at 2016-04-12 12:00 UTC, and ended at 16904\*1440\*60 +
+(12\*60\*60) seconds after the epoch, at 2016-04-13 12:00 UTC.
+
+<a id="rend-spec-v3.txt-2.2.2"></a>
+
+## When to publish a hidden service descriptor {#WHEN-HSDESC}
+
+Hidden services periodically publish their descriptor to the responsible
+HSDirs. The set of responsible HSDirs is determined as specified in
+\[WHERE-HSDESC\].
+
+Specifically, every time a hidden service publishes its descriptor, it also
+sets up a timer for a random time between 60 minutes and 120 minutes in the
+future. When the timer triggers, the hidden service needs to publish its
+descriptor again to the responsible HSDirs for that time period.
+\[TODO: Control republish period using a consensus parameter?\]
+
+<a id="rend-spec-v3.txt-2.2.2.1"></a>
+
+### Overlapping descriptors {#OVERLAPPING-DESCS}
+
+Hidden services need to upload multiple descriptors so that they can be
+reachable to clients with older or newer consensuses than them. Services
+need to upload their descriptors to the HSDirs *before* the beginning of
+each upcoming time period, so that they are readily available for clients to
+fetch them. Furthermore, services should keep uploading their old descriptor
+even after the end of a time period, so that they can be reachable by
+clients that still have consensuses from the previous time period.
+
+Hence, services maintain two active descriptors at every point. Clients on
+the other hand, don't have a notion of overlapping descriptors, and instead
+always download the descriptor for the current time period and shared random
+value. It's the job of the service to ensure that descriptors will be
+available for all clients. See section \[FETCHUPLOADDESC\] for how this is
+achieved.
+
+\[TODO: What to do when we run multiple hidden services in a single host?\]
+
+<a id="rend-spec-v3.txt-2.2.3"></a>
+
+## Where to publish a hidden service descriptor {#WHERE-HSDESC}
+
+This section specifies how the HSDir hash ring is formed at any given
+time. Whenever a time value is needed (e.g. to get the current time period
+number), we assume that clients and services use the valid-after time from
+their latest live consensus.
+
+The following consensus parameters control where a hidden service
+descriptor is stored;
+
+```text
+ hsdir_n_replicas = an integer in range [1,16] with default value 2.
+ hsdir_spread_fetch = an integer in range [1,128] with default value 3.
+ hsdir_spread_store = an integer in range [1,128] with default value 4.
+ (Until 0.3.2.8-rc, the default was 3.)
+```
+
+To determine where a given hidden service descriptor will be stored
+in a given period, after the blinded public key for that period is
+derived, the uploading or downloading party calculates:
+
+```text
+ for replicanum in 1...hsdir_n_replicas:
+ hs_service_index(replicanum) = H("store-at-idx" |
+ blinded_public_key |
+ INT_8(replicanum) |
+ INT_8(period_length) |
+ INT_8(period_num) )
+```
+
+where blinded_public_key is specified in section \[KEYBLIND\], period_length
+is the length of the time period in minutes, and period_num is calculated
+using the current consensus "valid-after" as specified in section
+\[TIME-PERIODS\].
+
+Then, for each node listed in the current consensus with the HSDir flag,
+we compute a directory index for that node as:
+
+```text
+ hs_relay_index(node) = H("node-idx" | node_identity |
+ shared_random_value |
+ INT_8(period_num) |
+ INT_8(period_length) )
+```
+
+where shared_random_value is the shared value generated by the authorities
+in section \[PUB-SHAREDRANDOM\], and node_identity is the ed25519 identity
+key of the node.
+
+Finally, for replicanum in 1...hsdir_n_replicas, the hidden service
+host uploads descriptors to the first hsdir_spread_store nodes whose
+indices immediately follow hs_service_index(replicanum). If any of those
+nodes have already been selected for a lower-numbered replica of the
+service, any nodes already chosen are disregarded (i.e. skipped over)
+when choosing a replica's hsdir_spread_store nodes.
+
+When choosing an HSDir to download from, clients choose randomly from
+among the first hsdir_spread_fetch nodes after the indices. (Note
+that, in order to make the system better tolerate disappearing
+HSDirs, hsdir_spread_fetch may be less than hsdir_spread_store.)
+Again, nodes from lower-numbered replicas are disregarded when
+choosing the spread for a replica.
+
+<a id="rend-spec-v3.txt-2.2.4"></a>
+
+## Using time periods and SRVs to fetch/upload HS descriptors {#FETCHUPLOADDESC}
+
+Hidden services and clients need to make correct use of time periods (TP)
+and shared random values (SRVs) to successfully fetch and upload
+descriptors. Furthermore, to avoid problems with skewed clocks, both clients
+and services use the 'valid-after' time of a live consensus as a way to take
+decisions with regards to uploading and fetching descriptors. By using the
+consensus times as the ground truth here, we minimize the desynchronization
+of clients and services due to system clock. Whenever time-based decisions
+are taken in this section, assume that they are consensus times and not
+system times.
+
+As \[PUB-SHAREDRANDOM\] specifies, consensuses contain two shared random
+values (the current one and the previous one). Hidden services and clients
+are asked to match these shared random values with descriptor time periods
+and use the right SRV when fetching/uploading descriptors. This section
+attempts to precisely specify how this works.
+
+Let's start with an illustration of the system:
+
+```text
+ +------------------------------------------------------------------+
+ | |
+ | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ | |
+ | $==========|-----------$===========|-----------$===========| |
+ | |
+ | |
+ +------------------------------------------------------------------+
+
+ Legend: [TP#1 = Time Period #1]
+ [SRV#1 = Shared Random Value #1]
+ ["$" = descriptor rotation moment]
+```
+
+<a id="rend-spec-v3.txt-2.2.4.1"></a>
+
+### Client behavior for fetching descriptors {#CLIENTFETCH}
+
+And here is how clients use TPs and SRVs to fetch descriptors:
+
+Clients always aim to synchronize their TP with SRV, so they always want to
+use TP#N with SRV#N: To achieve this wrt time periods, clients always use
+the current time period when fetching descriptors. Now wrt SRVs, if a client
+is in the time segment between a new time period and a new SRV (i.e. the
+segments drawn with "-") it uses the current SRV, else if the client is in a
+time segment between a new SRV and a new time period (i.e. the segments
+drawn with "="), it uses the previous SRV.
+
+Example:
+
+```text
++------------------------------------------------------------------+
+| |
+| 00:00 12:00 00:00 12:00 00:00 12:00 |
+| SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+| |
+| $==========|-----------$===========|-----------$===========| |
+| ^ ^ |
+| C1 C2 |
++------------------------------------------------------------------+
+```
+
+If a client (C1) is at 13:00 right after TP#1, then it will use TP#1 and
+SRV#1 for fetching descriptors. Also, if a client (C2) is at 01:00 right
+after SRV#2, it will still use TP#1 and SRV#1.
+
+<a id="rend-spec-v3.txt-2.2.4.2"></a>
+
+### Service behavior for uploading descriptors {#SERVICEUPLOAD}
+
+As discussed above, services maintain two active descriptors at any time. We
+call these the "first" and "second" service descriptors. Services rotate
+their descriptor every time they receive a consensus with a valid_after time
+past the next SRV calculation time. They rotate their descriptors by
+discarding their first descriptor, pushing the second descriptor to the
+first, and rebuilding their second descriptor with the latest data.
+
+Services like clients also employ a different logic for picking SRV and TP
+values based on their position in the graph above. Here is the logic:
+
+<a id="rend-spec-v3.txt-2.2.4.2.1"></a>
+
+#### First descriptor upload logic {#FIRSTDESCUPLOAD}
+
+Here is the service logic for uploading its first descriptor:
+
+When a service is in the time segment between a new time period a new SRV
+(i.e. the segments drawn with "-"), it uses the previous time period and
+previous SRV for uploading its first descriptor: that's meant to cover
+for clients that have a consensus that is still in the previous time period.
+
+Example: Consider in the above illustration that the service is at 13:00
+right after TP#1. It will upload its first descriptor using TP#0 and SRV#0.
+So if a client still has a 11:00 consensus it will be able to access it
+based on the client logic above.
+
+Now if a service is in the time segment between a new SRV and a new time
+period (i.e. the segments drawn with "=") it uses the current time period
+and the previous SRV for its first descriptor: that's meant to cover clients
+with an up-to-date consensus in the same time period as the service.
+
+Example:
+
+```text
++------------------------------------------------------------------+
+| |
+| 00:00 12:00 00:00 12:00 00:00 12:00 |
+| SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+| |
+| $==========|-----------$===========|-----------$===========| |
+| ^ |
+| S |
++------------------------------------------------------------------+
+```
+
+Consider that the service is at 01:00 right after SRV#2: it will upload its
+first descriptor using TP#1 and SRV#1.
+
+<a id="rend-spec-v3.txt-2.2.4.2.2"></a>
+
+#### Second descriptor upload logic {#SECONDDESCUPLOAD}
+
+Here is the service logic for uploading its second descriptor:
+
+When a service is in the time segment between a new time period a new SRV
+(i.e. the segments drawn with "-"), it uses the current time period and
+current SRV for uploading its second descriptor: that's meant to cover for
+clients that have an up-to-date consensus on the same TP as the service.
+
+Example: Consider in the above illustration that the service is at 13:00
+right after TP#1: it will upload its second descriptor using TP#1 and SRV#1.
+
+Now if a service is in the time segment between a new SRV and a new time
+period (i.e. the segments drawn with "=") it uses the next time period and
+the current SRV for its second descriptor: that's meant to cover clients
+with a newer consensus than the service (in the next time period).
+
+Example:
+
+```text
++------------------------------------------------------------------+
+| |
+| 00:00 12:00 00:00 12:00 00:00 12:00 |
+| SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+| |
+| $==========|-----------$===========|-----------$===========| |
+| ^ |
+| S |
++------------------------------------------------------------------+
+```
+
+Consider that the service is at 01:00 right after SRV#2: it will upload its
+second descriptor using TP#2 and SRV#2.
+
+<a id="rend-spec-v3.txt-2.2.4.3"></a>
+
+### Directory behavior for handling descriptor uploads \[DIRUPLOAD\]
+
+Upon receiving a hidden service descriptor publish request, directories MUST
+check the following:
+
+```text
+ * The outer wrapper of the descriptor can be parsed according to
+ [DESC-OUTER]
+ * The version-number of the descriptor is "3"
+ * If the directory has already cached a descriptor for this hidden service,
+ the revision-counter of the uploaded descriptor must be greater than the
+ revision-counter of the cached one
+ * The descriptor signature is valid
+```
+
+If any of these basic validity checks fails, the directory MUST reject the
+descriptor upload.
+
+NOTE: Even if the descriptor passes the checks above, its first and second
+layers could still be invalid: directories cannot validate the encrypted
+layers of the descriptor, as they do not have access to the public key of the
+service (required for decrypting the first layer of encryption), or the
+necessary client credentials (for decrypting the second layer).
+
+<a id="rend-spec-v3.txt-2.2.5"></a>
+
+## Expiring hidden service descriptors {#EXPIRE-DESC}
+
+Hidden services set their descriptor's "descriptor-lifetime" field to 180
+minutes (3 hours). Hidden services ensure that their descriptor will remain
+valid in the HSDir caches, by republishing their descriptors periodically as
+specified in \[WHEN-HSDESC\].
+
+Hidden services MUST also keep their introduction circuits alive for as long
+as descriptors including those intro points are valid (even if that's after
+the time period has changed).
+
+<a id="rend-spec-v3.txt-2.2.6"></a>
+
+## URLs for anonymous uploading and downloading {#urls}
+
+Hidden service descriptors conforming to this specification are uploaded
+with an HTTP POST request to the URL `/tor/hs/<version>/publish` relative to
+the hidden service directory's root, and downloaded with an HTTP GET
+request for the URL `/tor/hs/<version>/<z>` where `<z>` is a base64 encoding of
+the hidden service's blinded public key and `<version>` is the protocol
+version which is "3" in this case.
+
+These requests must be made anonymously, on circuits not used for
+anything else.
+
+<a id="rend-spec-v3.txt-2.2.7"></a>
+
+## Client-side validation of onion addresses {#addr-validation}
+
+When a Tor client receives a prop224 onion address from the user, it
+MUST first validate the onion address before attempting to connect or
+fetch its descriptor. If the validation fails, the client MUST
+refuse to connect.
+
+As part of the address validation, Tor clients should check that the
+underlying ed25519 key does not have a torsion component. If Tor accepted
+ed25519 keys with torsion components, attackers could create multiple
+equivalent onion addresses for a single ed25519 key, which would map to the
+same service. We want to avoid that because it could lead to phishing
+attacks and surprising behaviors (e.g. imagine a browser plugin that blocks
+onion addresses, but could be bypassed using an equivalent onion address
+with a torsion component).
+
+The right way for clients to detect such fraudulent addresses (which should
+only occur malevolently and never naturally) is to extract the ed25519
+public key from the onion address and multiply it by the ed25519 group order
+and ensure that the result is the ed25519 identity element. For more
+details, please see \[TORSION-REFS\].