summaryrefslogtreecommitdiff
path: root/anastasis.rst
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-07-18 07:37:58 +0200
committerChristian Grothoff <christian@grothoff.org>2021-07-18 07:37:58 +0200
commit996ce432b49ba3c75b21d14b8d2980c99684d1c2 (patch)
treef14d39329a338298fe51eec87411049fbb23fe2b /anastasis.rst
parentf4b5e48d5667e9eb4126aa8e060db0f041ef2318 (diff)
downloaddocs-996ce432b49ba3c75b21d14b8d2980c99684d1c2.tar.gz
docs-996ce432b49ba3c75b21d14b8d2980c99684d1c2.tar.bz2
docs-996ce432b49ba3c75b21d14b8d2980c99684d1c2.zip
moving Anastasis docu to Anastasis, fixing inconsistent licensing statements
Diffstat (limited to 'anastasis.rst')
-rw-r--r--anastasis.rst2705
1 files changed, 0 insertions, 2705 deletions
diff --git a/anastasis.rst b/anastasis.rst
deleted file mode 100644
index 0cca44b6..00000000
--- a/anastasis.rst
+++ /dev/null
@@ -1,2705 +0,0 @@
-..
- This file is part of Anastasis
- Copyright (C) 2019-2021 Anastasis SARL
-
- Anastasis is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2.1, or (at your option) any later version.
-
- Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License along with
- Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-
- @author Christian Grothoff
- @author Dominik Meister
- @author Dennis Neufeld
-
-=========
-Anastasis
-=========
-
-Anastasis is a service that allows the user to securely deposit a
-**core secret** with an open set of escrow providers and recover it if the secret is
-lost. The **core secret** itself is protected from the escrow providers by
-encrypting it with a **master key**. The main objective of Anastasis is to
-ensure that the user can reliably recover the **core secret**, while making
-this difficult for everyone else. Furthermore, it is assumed that the user is
-unable to reliably remember any secret with sufficiently high entropy, so we
-cannot simply encrypt using some other key material in possession of the user.
-
-To uniquely identify users, an "unforgettable" **identifier** is used. This
-identifier should be difficult to guess for anybody but the user. However, the
-**identifier** is not expected to have sufficient entropy or secrecy to be
-cryptographically secure. Examples for such identifier would be a
-concatenation of the full name of the user and their social security or
-passport number(s). For Swiss citizens, the AHV number could also be used.
-
-The adversary model of Anastasis has two types of adversaries: weak
-adversaries which do not know the user's **identifier**, and strong
-adversaries which somehow do know a user's **identifier**. For weak
-adversaries the system guarantees full confidentiality. For strong
-adversaries, breaking confidentiality additionally requires that Anastasis
-escrow providers must have colluded. The user is able to specify a set of
-**policies** which determine which Anastasis escrow providers would need to
-collude to break confidentiality. These policies also set the bar for the user
-to recover their core secret.
-
-A **recovery document** includes all of the information a user needs to
-recover access to their core secret. It specifies a set of **escrow
-methods**, which specify how the user should convince the Anastasis server
-that they are "real". Escrow methods can for example include SMS-based
-verification, video identification or a security question. For each escrow
-method, the Anastasis server is provided with **truth**, that is data the
-Anastasis operator may learn during the recovery process to authenticate the
-user. Examples for truth would be a phone number (for SMS), a picture of the
-user (for video identification), or the (hash of) a security answer. A strong
-adversary is assumed to be able to learn the truth, while weak adversaries
-must not. In addition to a set of escrow methods and associated Anastasis
-server operators, the **recovery document** also specifies **policies**, which
-describe the combination(s) of the escrow methods that suffice to obtain
-access to the core secret. For example, a **policy** could say that the
-escrow methods (A and B) suffice, and a second policy may permit (A and C). A
-different user may choose to use the policy that (A and B and C) are all
-required. Anastasis imposes no limit on the number of policies in a
-**recovery document**, or the set of providers or escrow methods involved in
-guarding a user's secret. Weak adversaries must not be able to deduce
-information about a user's **recovery document** (except for its length, which
-may be exposed to an adversary which monitors the user's network traffic).
-
-----------------------
-Anastasis Installation
-----------------------
-
-Please install the following packages before proceeding with the
-exchange compilation.
-
-.. include:: frags/list-of-dependencies.rst
-
-- GNU Taler exchange
-
-- GNU Taler merchant backend
-
-Except for the last two, these are available in most GNU/Linux distributions
-and should just be installed using the respective package manager.
-
-
-Installing from source
-----------------------
-
-The following instructions will show how to install libgnunetutil and
-the GNU Taler exchange from source.
-
-Installing GNUnet
-^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-gnunet.rst
-
-Installing the Taler Exchange
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-taler-exchange.rst
-
-Installing the Taler Merchant
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-taler-merchant.rst
-
-Installing Anastasis
-^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-anastasis.rst
-
-Installing GNUnet-gtk
-^^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-gnunet-gtk.rst
-
-Installing Anastasis-gtk
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. include:: frags/installing-anastasis-gtk.rst
-
-
-
-Installing Anastasis binary packages on Debian
-----------------------------------------------
-
-.. include:: frags/installing-debian.rst
-
-
-Installing the graphical front-end
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To install the Anastasis front-end, you can now simply run:
-
-.. code-block:: console
-
- # apt install -t sid anastasis-gtk
-
-To use ``anastasis-gtk``, you can simply run:
-
-.. code-block:: console
-
- $ anastasis-gtk
-
-Installing the backend
-^^^^^^^^^^^^^^^^^^^^^^
-
-If you want to install the Anastasis backend-end (which normal users do not
-need), you should run:
-
-.. code-block:: console
-
- # apt install -t sid anastasis-httpd
-
-Note that the latter package does not perform all of the configuration work.
-It does setup the user users and the systemd service scripts, but you still
-must configure the database backup, HTTP reverse proxy (typically with TLS
-certificates), Taler merchant backend for payments, authentication services,
-prices and the terms of service.
-
-Sample configuration files for the HTTP reverse proxy can be found in
-``/etc/anastasis.conf``.
-
-
-Installing Anastasis binary packages on Ubuntu
-----------------------------------------------
-
-.. include:: frags/installing-ubuntu.rst
-
-Installing the graphical front-end
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To install the Anastasis front-end, you can now simply run:
-
-.. code-block:: console
-
- # apt install -t focal-fossa anastasis-gtk
-
-To use ``anastasis-gtk``, you can simply run:
-
-.. code-block:: console
-
- $ anastasis-gtk
-
-Installing the backend
-^^^^^^^^^^^^^^^^^^^^^^
-
-If you want to install the Anastasis backend-end (which normal users do not
-need), you should run:
-
-.. code-block:: console
-
- # apt install -t focal-fossa anastasis-httpd
-
-Note that the latter package does not perform all of the configuration work.
-It does setup the user users and the systemd service scripts, but you still
-must configure the database backup, HTTP reverse proxy (typically with TLS
-certificates), Taler merchant backend for payments, authentication services,
-prices and the terms of service.
-
-Sample configuration files for the HTTP reverse proxy can be found in
-``/etc/anastasis.conf``.
-
-
-----------------------
-Anastasis Cryptography
-----------------------
-
-When a user needs to interact with Anastasis, the system first derives some key
-material, but not the master secret, from the user's **identifier** using
-different HKDFs. These HKDFs are salted using the respective escrow
-provider's **server salt**, which ensures that the accounts for the same user
-cannot be easily correlated across the various Anastasis servers.
-
-Each Anastasis server uses an EdDSA **account key** to identify the account of
-the user. The account private key is derived from the user's **identifier** using
-a computationally expensive cryptographic hash function. Using an
-expensive hash algorithm is assumed to make it infeasible for a weak adversary to
-determine account keys by brute force (without knowing the user's identifier).
-However, it is assumed that a strong adversary performing a targeted attack can
-compute the account key pair.
-
-The public account key is Crockford base32-encoded in the URI to identify the
-account, and used to sign requests. These signatures are also provided in
-base32-encoding and transmitted using the HTTP header
-``Anastasis-Account-Signature``.
-
-When confidential data is uploaded to an Anastasis server, the respective
-payload is encrypted using AES-GCM with a symmetric key and initialization
-vector derived from the **identifier** and a high-entropy **nonce**. The
-nonce and the GCM tag are prepended to the ciphertext before being uploaded to
-the Anastasis server. This is done whenever confidential data is stored with
-the server.
-
-The **core secret** of the user is (AES) encrypted using a symmetric **master
-key**. Recovering this master key requires the user to satisfy a particular
-**policy**. Policies specify a set of **escrow methods**, each of which leads
-the user to a **key share**. Combining those key shares (by hashing) allows
-the user to obtain a **policy key**, which can be used to decrypt the **master
-key**. There can be many policies, satisfying any of these will allow the
-user to recover the master key. A **recovery document** contains the
-encrypted **core secret**, a set of escrow methods and a set of policies.
-
-
-
-
-Key derivations
-^^^^^^^^^^^^^^^
-
-EdDSA and ECDHE public keys are always points on Curve25519 and represented
-using the standard 256 bit Ed25519 compact format. The binary representation
-is converted to Crockford Base32 when transmitted inside JSON or as part of
-URLs.
-
-To start, a user provides their private, unique and unforgettable
-**identifier** as a seed to identify their account. For example, this could
-be a social security number together with their full name. Specifics may
-depend on the cultural context, in this document we will simply refer to this
-information as the **identifier**.
-
-This identifier will be first hashed with Argon2, to provide a **kdf_id**
-which will be used to derive other keys later. The Hash must also include the
-respective **server_salt**. This also ensures that the **kdf_id** is different
-on each server. The use of Argon2 and the respective **server_salt** is intended
-to make it difficult to brute-force **kdf_id** values and help protect the user's
-privacy. Also this ensures that the **kdf_id**\ s on every server differs. However,
-we do not assume that the **identifier** or the **kdf_id** cannot be
-determined by an adversary performing a targeted attack, as a user's
-**identifier** is likely to always be known to state actors and may
-likely also be available to other actors.
-
-
-.. code-block:: none
-
- kdf_id := Argon2( identifier, server_salt, keysize )
-
-**identifier**: The secret defined from the user beforehand.
-
-**server_salt**: The salt from the Server.
-
-**keysize**: The desired output size of the KDF, here 32 bytes.
-
-
-Verification
-------------
-
-For users to authorize "policy" operations we need an EdDSA key pair. As we
-cannot assure that the corresponding private key is truly secret, such policy
-operations must never be destructive: Should an adversary learn the private
-key, they could access (and with the **kdf_id**, decrypt) the user's policy (but
-not the core secret), or upload a new version of the
-**encrypted recovery document** (but not delete an existing version).
-
-For the generation of the private key we use the **kdf_id** as the entropy source,
-hash it to derive a base secret which will then be processed to fit the
-requirements for EdDSA private keys. From the private key we can then
-generate the corresponding public key. Here, "ver" is used as a salt for the
-HKDF to ensure that the result differs from other cases where we hash
-**kdf_id**.
-
-.. code-block:: none
-
- ver_secret := HKDF(kdf_id, "ver", keysize)
- eddsa_priv := eddsa_d_to_a(ver_secret)
- eddsa_pub := get_EdDSA_Pub(eddsa_priv)
-
-
-**HKDF()**: The HKDF-function uses two phases: First we use HMAC-SHA512 for the extraction phase, then HMAC-SHA256 is used for expansion phase.
-
-**kdf_id**: Hashed identifier.
-
-**key_size**: Size of the output, here 32 bytes.
-
-**ver_secret**: Derived key from the ``kdf_id``, serves as intermediate step for the generation of the private key.
-
-**eddsa_d_to_a()**: Function which converts the ver_key to a valid EdDSA private key. Specifically, assuming the value ``eddsa_priv`` is in a 32-byte array "digest", the function clears and sets certain bits as follows:
-
-.. code-block:: c
-
- digest[0] = (digest[0] & 0x7f) | 0x40;
- digest[31] &= 0xf8;
-
-**eddsa_priv**: The generated EdDSA private key.
-
-**eddsa_pub**: The generated EdDSA public key.
-
-
-Encryption
-----------
-
-For symmetric encryption of data we use AES256-GCM. For this we need a
-symmetric key and an initialization vector (IV). To ensure that the
-symmetric key changes for each encryption operation, we compute the
-key material using an HKDF over a ``nonce`` and the ``kdf_id``.
-
-.. code-block:: none
-
- (iv,key) := HKDF(kdf_id, nonce, keysize + ivsize)
-
-**HKDF()**: The HKDF-function uses two phases: First we use HMAC-SHA512 for the extraction phase, then HMAC-SHA256 is used for expansion phase.
-
-**kdf_id**: Hashed identifier.
-
-**keysize**: Size of the AES symmetric key, here 32 bytes.
-
-**ivsize**: Size of the AES GCM IV, here 12 bytes.
-
-**prekey**: Original key material.
-
-**nonce**: 32-byte nonce, must never match "ver" (which it cannot as the length is different). Of course, we must
-avoid key reuse. So, we have to use different nonces to get different keys and IVs (see below).
-
-**key**: Symmetric key which is later used to encrypt the documents with AES256-GCM.
-
-**iv**: IV which will be used for AES-GCM.
-
-
-
-Key Usage
-^^^^^^^^^
-
-The keys we have generated are then used to encrypt the **recovery document** and
-the **key_share** of the user.
-
-
-Encryption
-----------
-
-Before every encryption a 32-byte nonce is generated.
-From this the symmetric key is computed as described above.
-We use AES256-GCM for the encryption of the **recovery document** and
-the **key_share**. To ensure that the key derivation for the encryption
-of the **recovery document** differs fundamentally from that of an
-individual **key share**, we use different salts ("erd" and "eks", respectively).
-
-.. code-block:: none
-
- (iv0, key0) := HKDF(key_id, nonce0, "erd", keysize + ivsize)
- (encrypted_recovery_document, aes_gcm_tag) := AES256_GCM(recovery_document, key0, iv0)
- (iv_i, key_i) := HKDF(key_id, nonce_i, "eks", [optional data], keysize + ivsize)
- (encrypted_key_share_i, aes_gcm_tag_i) := AES256_GCM(key_share_i, key_i, iv_i)
-
-**encrypted_recovery_document**: The encrypted **recovery document** which contains the escrow methods, policies
-and the encrypted **core secret**.
-
-**nonce0**: Nonce which is used to generate *key0* and *iv0* which are used for the encryption of the *recovery document*.
-Nonce must contain the string "ERD".
-
-**optional data**: Key material that optionally is contributed from the authentication method to further obfuscate the key share from the escrow provider.
-
-**encrypted_key_share_i**: The encrypted **key_share** which the escrow provider must release upon successful authentication.
-Here, **i** must be a positive number used to iterate over the various **key shares** used for the various **escrow methods**
-at the various providers.
-
-**nonce_i**: Nonce which is used to generate *key_i* and *iv_i* which are used for the encryption of the **key share**. **i** must be
-the same number as specified above for *encrypted_key_share_i*. Nonce must contain the string "EKS" plus the according *i*.
-
-As a special rule, when a **security question** is used to authorize access to an
-**encrypted_key_share_i**, then the salt "eks" is replaced with an (expensive) hash
-of the answer to the security question as an additional way to make the key share
-inaccessible to those who do not have the answer:
-
-.. code-block:: none
-
- powh := POW_HASH (qsalt, answer)
- ekss := HKDF("Anastasis-secure-question-uuid-salting",
- powh,
- uuid);
- (iv_i, key_i) := HKDF(key_id, nonce_i, ekss, [optional data], keysize + ivsize)
-
-
-**qsalt**: Salt value used to hash answer to satisfy the challenge to prevent the provider from determining the answer via guessing.
-
-**answer**: Answer to the security question, in UTF-8, as entered by the user.
-
-**powh**: Result of the (expensive, proof-of-work) hash algorithm.
-
-**uuid**: UUID of the challenge associated with the security question and the encrypted key share.
-
-**ekss**: Replacement salt to be used instead of "eks" when deriving the key to encrypt/decrypt the key share.
-
-
-Signatures
-----------
-
-The EdDSA keys are used to sign the data sent from the client to the
-server. Everything the client sends to server is signed. The following
-algorithm is equivalent for **Anastasis-Policy-Signature**.
-
-.. code-block:: none
-
- (anastasis-account-signature) := eddsa_sign(h_body, eddsa_priv)
- ver_res := eddsa_verifiy(h_body, anastasis-account-signature, eddsa_pub)
-
-**anastasis-account-signature**: Signature over the SHA-512 hash of the body using the purpose code ``TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD`` (1400) (see GNUnet EdDSA signature API for the use of purpose).
-
-**h_body**: The hashed body.
-
-**ver_res**: A boolean value. True: Signature verification passed, False: Signature verification failed.
-
-
-When requesting policy downloads, the client must also provide a signature:
-
-.. code-block:: none
-
- (anastasis-account-signature) := eddsa_sign(version, eddsa_priv)
- ver_res := eddsa_verifiy(version, anastasis-account-signature, eddsa_pub)
-
-**anastasis-account-signature**: Signature over the SHA-512 hash of the body using the purpose code ``TALER_SIGNATURE_ANASTASIS_POLICY_DOWNLOAD`` (1401) (see GNUnet EdDSA signature API for the use of purpose).
-
-**version**: The version requested as a 64-bit integer, 2^64-1 for the "latest version".
-
-**ver_res**: A boolean value. True: Signature verification passed, False: Signature verification failed.
-
-
-
-Availability Considerations
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Anastasis considers two main threats against availability. First, the
-Anastasis server operators must be protected against denial-of-service attacks
-where an adversary attempts to exhaust the operator's resources. The API protects
-against these attacks by allowing operators to set fees for all
-operations. Furthermore, all data stored comes with an expiration logic, so an
-attacker cannot force servers to store data indefinitely.
-
-A second availability issue arises from strong adversaries that may be able to
-compute the account keys of some user. While we assume that such an adversary
-cannot successfully authenticate against the truth, the account key does
-inherently enable these adversaries to upload a new policy for the account.
-This cannot be prevented, as the legitimate user must be able to set or change
-a policy using only the account key. To ensure that an adversary cannot
-exploit this, policy uploads first of all never delete existing policies, but
-merely create another version. This way, even if an adversary uploads a
-malicious policy, a user can still retrieve an older version of the policy to
-recover access to their data. This append-only storage for policies still
-leaves a strong adversary with the option of uploading many policies to
-exhaust the Anastasis server's capacity. We limit this attack by requiring a
-policy upload to include a reference to a **payment identifier** from a payment
-made by the user. Thus, a policy upload requires both knowledge of the
-**identity** and making a payment. This effectively prevents an adversary
-from using the append-only policy storage from exhausting Anastasis server
-capacity.
-
-
-
-------------------
-Anastasis REST API
-------------------
-
-.. _salt:
-.. _config:
-
-Receiving Configuration
-^^^^^^^^^^^^^^^^^^^^^^^
-
-.. http:get:: /config
-
- Obtain the configuration details of the escrow provider.
-
- **Response:**
-
- Returns an `EscrowConfigurationResponse`_.
-
-
- .. _EscrowConfigurationResponse:
- .. ts:def:: EscrowConfigurationResponse
-
- interface EscrowConfigurationResponse {
-
- // Protocol identifier, clarifies that this is an Anastasis provider.
- name: "anastasis";
-
- // libtool-style representation of the Exchange protocol version, see
- // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
- // The format is "current:revision:age".
- version: string;
-
- // Currency in which this provider processes payments.
- currency: string;
-
- // Supported authorization methods.
- methods: AuthorizationMethodConfig[];
-
- // Maximum policy upload size supported.
- storage_limit_in_megabytes: number;
-
- // Payment required to maintain an account to store policy documents for a year.
- // Users can pay more, in which case the storage time will go up proportionally.
- annual_fee: Amount;
-
- // Payment required to upload truth. To be paid per upload.
- truth_upload_fee: Amount;
-
- // Limit on the liability that the provider is offering with
- // respect to the services provided.
- liability_limit: Amount;
-
- // Salt value with 128 bits of entropy.
- // Different providers
- // will use different high-entropy salt values. The resulting
- // **provider salt** is then used in various operations to ensure
- // cryptographic operations differ by provider. A provider must
- // never change its salt value.
- server_salt: string;
-
- }
-
- .. _AuthorizationMethodConfig:
- .. ts:def:: AuthorizationMethodConfig
-
- interface AuthorizationMethodConfig {
- // Name of the authorization method.
- type: string;
-
- // Fee for accessing key share using this method.
- cost: Amount;
-
- }
-
-.. _terms:
-
-Receiving Terms of Service
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. http:get:: /terms
-
- Obtain the terms of service provided by the escrow provider.
-
- **Response:**
-
- Returns the terms of service of the provider, in the best language
- and format available based on the client's request.
-
-.. http:get:: /privacy
-
- Obtain the privacy policy of the service provided by the escrow provider.
-
- **Response:**
-
- Returns the privacy policy of the provider, in the best language
- and format available based on the client's request.
-
-
-.. _manage-policy:
-
-
-Manage policy
-^^^^^^^^^^^^^
-
-This API is used by the Anastasis client to deposit or request encrypted
-recovery documents with the escrow provider. Generally, a client will deposit
-the same encrypted recovery document with each escrow provider, but provide
-a different truth to each escrow provider.
-
-Operations by the client are identified and authorized by ``$ACCOUNT_PUB``, which
-should be kept secret from third parties. ``$ACCOUNT_PUB`` should be an account
-public key using the Crockford base32-encoding.
-
-In the following, UUID is always defined and used according to `RFC 4122`_.
-
-.. _`RFC 4122`: https://tools.ietf.org/html/rfc4122
-
-.. http:get:: /policy/$ACCOUNT_PUB[?version=$NUMBER]
-
- Get the customer's encrypted recovery document. If ``version``
- is not specified, the server returns the latest available version. If
- ``version`` is specified, returns the policy with the respective
- ``version``. The response must begin with the nonce and
- an AES-GCM tag and continue with the ciphertext. Once decrypted, the
- plaintext is expected to contain:
-
- * the escrow policy
- * the separately encrypted master public key
-
- Note that the key shares required to decrypt the master public key are
- not included, as for this the client needs to obtain authorization.
- The policy does provide sufficient information for the client to determine
- how to authorize requests for **truth**.
-
- The client MAY provide an ``If-None-Match`` header with an Etag.
- In that case, the server MUST additionally respond with an ``304`` status
- code in case the resource matches the provided Etag.
-
- **Response**:
-
- :http:statuscode:`200 OK`:
- The escrow provider responds with an EncryptedRecoveryDocument_ object.
- :http:statuscode:`304 Not modified`:
- The client requested the same resource it already knows.
- :http:statuscode:`400 Bad request`:
- The ``$ACCOUNT_PUB`` is not an EdDSA public key.
- :http:statuscode:`402 Payment Required`:
- The account's balance is too low for the specified operation.
- See the Taler payment protocol specification for how to pay.
- :http:statuscode:`403 Forbidden`:
- The required account signature was invalid.
- :http:statuscode:`404 Not found`:
- The requested resource was not found.
-
- *Anastasis-Version*: $NUMBER --- The server must return actual version of the encrypted recovery document via this header.
- If the client specified a version number in the header of the request, the server must return that version. If the client
- did not specify a version in the request, the server returns latest version of the EncryptedRecoveryDocument_.
-
- *Etag*: Set by the server to the Base32-encoded SHA512 hash of the body. Used for caching and to prevent redundancies. The server MUST send the Etag if the status code is ``200 OK``.
-
- *If-None-Match*: If this is not the very first request of the client, this contains the Etag-value which the client has received before from the server.
- The client SHOULD send this header with every request (except for the first request) to avoid unnecessary downloads.
-
- *Anastasis-Account-Signature*: The client must provide Base-32 encoded EdDSA signature over hash of body with ``$ACCOUNT_PRIV``, affirming desire to download the requested encrypted recovery document. The purpose used MUST be ``TALER_SIGNATURE_ANASTASIS_POLICY_DOWNLOAD`` (1401).
-
-.. http:post:: /policy/$ACCOUNT_PUB
-
- Upload a new version of the customer's encrypted recovery document.
- While the document's structure is described in JSON below, the upload
- should just be the bytestream of the raw data (i.e. 32-byte nonce followed
- by 16-byte tag followed by the encrypted document).
- If the request has been seen before, the server should do nothing, and otherwise store the new version.
- The body must begin with a nonce, an AES-GCM tag and continue with the ciphertext. The format
- is the same as specified for the response of the GET method. The
- Anastasis server cannot fully validate the format, but MAY impose
- minimum and maximum size limits.
-
- **Request**:
-
- :query storage_duration=YEARS:
- For how many years from now would the client like us to
- store the recovery document? Defaults to 0 (that is, do
- not extend / prolong existing storage contract).
- The server will respond with a ``402 Payment required``, but only
- if the rest of the request is well-formed (account
- signature must match). Clients that do not actually
- intend to make a new upload but that only want to pay
- may attempt to upload the latest backup again, as this
- option will be checked before the ``304 Not modified``
- case.
- :query timeout_ms=NUMBER: *Optional.* If specified, the Anastasis server will
- wait up to ``timeout_ms`` milliseconds for completion of the payment before
- sending the HTTP response. A client must never rely on this behavior, as the
- backend may return a response immediately.
-
- *If-None-Match*: This header MUST be present and set to the SHA512 hash (Etag) of the body by the client.
- The client SHOULD also set the ``Expect: 100-Continue`` header and wait for ``100 continue``
- before uploading the body. The server MUST
- use the Etag to check whether it already knows the encrypted recovery document that is about to be uploaded.
- The server MUST refuse the upload with a ``304`` status code if the Etag matches
- the latest version already known to the server.
-
- *Anastasis-Policy-Signature*: The client must provide Base-32 encoded EdDSA signature over hash of body with ``$ACCOUNT_PRIV``, affirming desire to upload an encrypted recovery document.
-
- *Payment-Identifier*: Base-32 encoded 32-byte payment identifier that was included in a previous payment (see ``402`` status code). Used to allow the server to check that the client paid for the upload (to protect the server against DoS attacks) and that the client knows a real secret of financial value (as the **kdf_id** might be known to an attacker). If this header is missing in the client's request (or the associated payment has exceeded the upload limit), the server must return a ``402`` response. When making payments, the server must include a fresh, randomly-generated payment-identifier in the payment request.
-
- **Response**:
-
- :http:statuscode:`204 No content`:
- The encrypted recovery document was accepted and stored. ``Anastasis-Version`` and ``Anastasis-UUID`` headers
- indicate what version and UUID was assigned to this encrypted recovery document upload by the server.
- :http:statuscode:`304 Not modified`:
- The same encrypted recovery document was previously accepted and stored. ``Anastasis-Version`` header
- indicates what version was previously assigned to this encrypted recovery document.
- :http:statuscode:`400 Bad request`:
- The ``$ACCOUNT_PUB`` is not an EdDSA public key or mandatory headers are missing.
- The response body MUST elaborate on the error using a Taler error code in the typical JSON encoding.
- :http:statuscode:`402 Payment required`:
- The account's balance is too low for the specified operation.
- See the Taler payment protocol specification for how to pay.
- The response body MAY provide alternative means for payment.
- :http:statuscode:`403 Forbidden`:
- The required account signature was invalid. The response body may elaborate on the error.
- :http:statuscode:`413 Request entity too large`:
- The upload is too large *or* too small. The response body may elaborate on the error.
-
- **Details:**
-
- .. _EncryptedRecoveryDocument:
- .. ts:def:: EncryptedRecoveryDocument
-
- interface EncryptedRecoveryDocument {
- // Nonce used to compute the (iv,key) pair for encryption of the
- // encrypted_compressed_recovery_document.
- nonce: [32]; //bytearray
-
- // Authentication tag.
- aes_gcm_tag: [16]; //bytearray
-
- // Variable-size encrypted recovery document. After decryption,
- // this contains a gzip compressed JSON-encoded `RecoveryDocument`.
- // The nonce of the HKDF for this encryption must include the
- // string "ERD".
- encrypted_compressed_recovery_document: []; //bytearray of undefined length
-
- }
-
- .. _RecoveryDocument:
- .. ts:def:: RecoveryDocument
-
- interface RecoveryDocument {
- // Account identifier at backup provider, AES-encrypted with
- // the (symmetric) master_key, i.e. an URL
- // https://sync.taler.net/$BACKUP_ID and
- // a private key to decrypt the backup. Anastasis is oblivious
- // to the details of how this is ultimately encoded.
- backup_account: []; //bytearray of undefined length
-
- // List of escrow providers and selected authentication method.
- methods: EscrowMethod[];
-
- // List of possible decryption policies.
- policy: DecryptionPolicy[];
-
- }
-
- .. _EscrowMethod:
- .. ts:def:: EscrowMethod
-
- interface EscrowMethod {
- // URL of the escrow provider (including possibly this Anastasis server).
- provider_url : string;
-
- // Type of the escrow method (e.g. security question, SMS etc.).
- escrow_type: string;
-
- // UUID of the escrow method (see /truth/ API below).
- uuid: string;
-
- // Key used to encrypt the `Truth` this `EscrowMethod` is related to.
- // Client has to provide this key to the server when using ``/truth/``.
- truth_encryption_key: [32]; //bytearray
-
- // Salt used to encrypt the truth on the Anastasis server.
- truth_salt: [32]; //bytearray
-
- // The challenge to give to the user (i.e. the security question
- // if this is challenge-response).
- // (Q: as string in base32 encoding?)
- // (Q: what is the mime-type of this value?)
- //
- // For some methods, this value may be absent.
- //
- // The plaintext challenge is not revealed to the
- // Anastasis server.
- challenge: []; //bytearray of undefined length
-
- }
-
- .. _DecryptionPolicy:
- .. ts:def:: DecryptionPolicy
-
- interface DecryptionPolicy {
- // Salt included to encrypt master key share when
- // using this decryption policy.
- policy_salt: [32]; //bytearray
-
- // Master key, AES-encrypted with key derived from
- // salt and keyshares revealed by the following list of
- // escrow methods identified by UUID.
- encrypted_master_key: [32]; //bytearray
-
- // List of escrow methods identified by their UUID.
- uuid: string[];
-
- }
-
-.. _Truth:
-
-Managing truth
-^^^^^^^^^^^^^^
-
-This API is used by the Anastasis client to deposit **truth** or request a (encrypted) **key share** with
-the escrow provider.
-
-An **escrow method** specifies an Anastasis provider and how the user should
-authorize themself. The **truth** API allows the user to provide the
-(encrypted) key share to the respective escrow provider, as well as auxiliary
-data required for such a respective escrow method.
-
-An Anastasis-server may store truth for free for a certain time period, or
-charge per truth operation using GNU Taler.
-
-.. http:post:: /truth/$UUID
-
- Upload a `TruthUploadRequest`_-Object according to the policy the client created before (see `RecoveryDocument`_).
- If request has been seen before, the server should do nothing, and otherwise store the new object.
-
- **Request:**
-
- :query timeout_ms=NUMBER: *Optional.* If specified, the Anastasis server will
- wait up to ``timeout_ms`` milliseconds for completion of the payment before
- sending the HTTP response. A client must never rely on this behavior, as the
- backend may return a response immediately.
-
- **Response:**
-
- :http:statuscode:`204 No content`:
- Truth stored successfully.
- :http:statuscode:`304 Not modified`:
- The same truth was previously accepted and stored under this UUID. The
- Anastasis server must still update the expiration time for the truth when returning
- this response code.
- :http:statuscode:`402 Payment required`:
- This server requires payment to store truth per item.
- See the Taler payment protocol specification for how to pay.
- The response body MAY provide alternative means for payment.
- :http:statuscode:`409 Conflict`:
- The server already has some truth stored under this UUID. The client should check that it
- is generating UUIDs with enough entropy.
- :http:statuscode:`412 Precondition failed`:
- The selected authentication method is not supported on this provider.
-
-
- **Details:**
-
- .. _TruthUploadRequest:
- .. ts:def:: TruthUploadRequest
-
- interface TruthUploadRequest {
- // Contains the information of an interface `EncryptedKeyShare`, but simply
- // as one binary block (in Crockford Base32 encoding for JSON).
- key_share_data: []; //bytearray
-
- // Key share method, i.e. "security question", "SMS", "e-mail", ...
- type: string;
-
- // Nonce used to compute the (iv,key) pair for encryption of the
- // encrypted_truth.
- nonce: [32]; //bytearray
-
- // Authentication tag of ``encrypted_truth``.
- aes_gcm_tag: [16]; //bytearray
-
- // Variable-size truth. After decryption,
- // this contains the ground truth, i.e. H(challenge answer),
- // phone number, e-mail address, picture, fingerprint, ...
- // **base32 encoded**.
- //
- // The nonce of the HKDF for this encryption must include the
- // string "ECT".
- encrypted_truth: [80]; //bytearray
-
- // MIME type of truth, i.e. text/ascii, image/jpeg, etc.
- truth_mime: string;
-
- // For how many years from now would the client like us to
- // store the truth?
- storage_duration_years: integer;
-
- }
-
-.. http:get:: /truth/$UUID[?response=$H_RESPONSE]
-
- Get the stored encrypted key share. If ``$H_RESPONSE`` is specified by the client, the server checks
- if ``$H_RESPONSE`` matches the expected response specified before within the `TruthUploadRequest`_ (see ``encrypted_truth``).
- Also, the user has to provide the correct *truth_encryption_key* with every get request (see below).
- When ``$H_RESPONSE`` is correct, the server responds with the encrypted key share.
- The encrypted key share is returned simply as a byte array and not in JSON format.
-
- **Response**:
-
- :http:statuscode:`200 OK`:
- `EncryptedKeyShare`_ is returned in body (in binary).
- :http:statuscode:`202 Accepted`:
- The escrow provider will respond out-of-band (i.e. SMS).
- The body may contain human-readable instructions on next steps.
- :http:statuscode:`208 Already Reported`:
- An authentication challenge was recently send, client should
- simply respond to the pending challenge.
- :http:statuscode:`303 See other`:
- The provider redirects for authentication (i.e. video identification/WebRTC).
- If the client is not a browser, it should launch a browser at the URL
- given in the ``Location`` header and allow the user to re-try the operation
- after successful authorization.
- :http:statuscode:`402 Payment required`:
- The service requires payment for access to truth.
- See the Taler payment protocol specification for how to pay.
- The response body MAY provide alternative means for payment.
- :http:statuscode:`403 Forbidden`:
- The server requires a valid "response" to the challenge associated with the UUID.
- :http:statuscode:`404 Not found`:
- The server does not know any truth under the given UUID.
- :http:statuscode:`410 Gone`:
- The server has not (recently) issued a challenge under the given UUID,
- but a reply was provided. (This does not apply for secure question.)
- :http:statuscode:`417 Expectation Failed`:
- The decrypted ``truth`` does not match the expectations of the authentication
- backend, i.e. a phone number for sending an SMS is not a number, or
- an e-mail address for sending an E-mail is not a valid e-mail address.
- :http:statuscode:`503 Service Unavailable`:
- Server is out of Service.
-
- *Truth-Decryption-Key*: Key used to encrypt the **truth** (see encrypted_truth within `TruthUploadRequest`_) and which has to provided by the user. The key is stored with
- the according `EscrowMethod`_. The server needs this key to get the info out of `TruthUploadRequest`_ needed to verify the ``$RESPONSE``.
-
- **Details:**
-
- .. _EncryptedKeyShare:
- .. ts:def:: EncryptedKeyShare
-
- interface EncryptedKeyShare {
- // Nonce used to compute the decryption (iv,key) pair.
- nonce_i: [32]; //bytearray
-
- // Authentication tag.
- aes_gcm_tag_i: [16]; //bytearray
-
- // Encrypted key-share in base32 encoding.
- // After decryption, this yields a `KeyShare`. Note that
- // the `KeyShare` MUST be encoded as a fixed-size binary
- // block (instead of in JSON encoding).
- //
- // HKDF for the key generation must include the
- // string "eks" as salt.
- // Depending on the method,
- // the HKDF may additionally include
- // bits from the response (i.e. some hash over the
- // answer to the security question).
- encrypted_key_share_i: [32]; //bytearray
-
- }
-
- .. _KeyShare:
- .. ts:def:: KeyShare
-
- interface KeyShare {
- // Key material to concatenate with policy_salt and KDF to derive
- // the key to decrypt the master key.
- key_share: [32]; //bytearray
-
- // Signature over method, UUID, and ``key_share``.
- account_sig: EddsaSignature;
-
- }
-
-
----------------------
-Anastasis Reducer API
----------------------
-
-This section describes the Anastasis Reducer API which is used by client applications
-to store or load the different states the client application can have.
-The reducer takes a state_ in JSON syntax and returns the new state in JSON syntax.
-
-For example a **state** may take the following structure:
-
-.. code-block:: json
-
- {
- "backup_state": "CONTINENT_SELECTING",
- "continents": [
- "Europe",
- "North_America"
- ]
- }
-
-The new state depends on the previous one and on the transition action_ with its
-arguments given to the reducer. A **transition argument** also is a statement in JSON syntax:
-
-.. code-block:: json
-
- {
- "continent": "Europe"
- }
-
-The new state returned by the reducer with the state and transition argument defined
-above would look like following for the transition action_ ``select_continent``:
-
-.. code-block:: json
-
- {
- "backup_state": "COUNTRY_SELECTING",
- "continents": [
- "Europe",
- "North_America"
- ],
- "selected_continent": "Europe",
- "countries": [
- {
- "code": "ch",
- "name": "Switzerland",
- "continent": "Europe",
- "name_i18n": {
- "de_DE": "Schweiz",
- "de_CH": "Schwiiz",
- "fr": "Suisse",
- "en": "Swiss"
- },
- "currency": "CHF"
- },
- {
- "code": "de",
- "name": "Germany",
- "continent": "Europe",
- "continent_i18n": {
- "de": "Europa"
- },
- "name_i18n": {
- "de_DE": "Deutschland",
- "de_CH": "Deutschland",
- "fr": "Allemagne",
- "en": "Germany"
- },
- "currency": "EUR"
- }
- ]
- }
-
-States
-^^^^^^
-
-Overall, the reducer knows the following states:
-
- - **ERROR**: The transition led to an error. No further transitions are possible from
- this state, but the client may want to continue from a previous state.
- - **CONTINENT_SELECTING**: The user should specify the continent where they are living,
- so that we can show a list of countries to choose from.
- - **COUNTRY_SELECTING**: The user should specify the country where they are living,
- so that we can determine appropriate attributes, currencies and Anastasis
- providers.
- - **USER_ATTRIBUTES_COLLECTING**: The user should provide the country-specific personal
- attributes.
- - **AUTHENTICATIONS_EDITING**: The user should add authentication methods to be used
- during recovery.
- - **POLICIES_REVIEWING**: The user should review the recovery policies.
- - **SECRET_EDITING**: The user should edit the secret to be backed up.
- - **TRUTHS_PAYING**: The user needs to pay for one or more uploads of data associated
- with an authentication method.
- - **POLICIES_PAYING**: The user needs to pay for storing the recovery policy document.
- - **BACKUP_FINISHED**: A backup has been successfully generated.
- - **SECRET_SELECTING**: The user needs to select a recovery policy document with
- the secret that is to be recovered.
- - **CHALLENGE_SELECTING**: The user needs to select an authorization challenge to
- proceed with recovery.
- - **CHALLENGE_PAYING**: The user needs to pay to proceed with the authorization challenge.
- - **CHALLENGE_SOLVING**: The user needs to solve the authorization challenge.
- - **RECOVERY_FINISHED**: The secret of the user has been recovered.
-
-State names:
-
- - In SELECTING-states, the user has to choose one value out of a predefined set of values (for example a continent out of a set of continents).
- - In COLLECTING-states, the user has to give certain values.
- - In EDITING-states, the user is free to choose which values he wants to give.
- - In REVEIWING-states, the user may make a few choices, but primarily is expected to affirm something.
- - in PAYING-states, the user must make a payment.
- - in FINISHED-states, the operation has definitively concluded.
-
-
-Backup Reducer
-^^^^^^^^^^^^^^
-.. _state:
-.. _action:
-.. figure:: anastasis_reducer_backup.png
- :name: fig-anastasis_reducer_backup
- :alt: fig-anastasis_reducer_backup
- :scale: 75 %
- :align: center
-
- Backup states and their transitions.
-
-
-The illustration above shows the different states the reducer can have during a backup
-process.
-
-
-Recovery Reducer
-^^^^^^^^^^^^^^^^
-.. figure:: anastasis_reducer_recovery.png
- :name: fig-anastasis_reducer_recovery
- :alt: fig-anastasis_reducer_recovery
- :scale: 75 %
- :align: center
-
- Recovery states and their transitions.
-
-
-The illustration above shows the different states the reducer can have during a recovery
-process.
-
-
-Reducer transitions
-^^^^^^^^^^^^^^^^^^^
-In the following, the individual transitions will be specified in more detail.
-Note that we only show fields added by the reducer, typically the previous
-state is preserved to enable "back" transitions to function smoothly.
-
-
-Initial state
--------------
-
-The initial states for backup and recovery processes are:
-
-**Initial backup state:**
-
-.. code-block:: json
-
- {
- "backup_state": "CONTINENT_SELECTING",
- "continents": [
- "Europe",
- "North America"
- ]
- }
-
-
-**Initial recovery state:**
-
-.. code-block:: json
-
- {
- "recovery_state": "CONTINENT_SELECTING",
- "continents": [
- "Europe",
- "North America"
- ]
- }
-
-Here, "continents" is an array of English strings with the names of the
-continents which contain countries for which Anastasis could function (based
-on having providers that are known to operate and rules being provided for
-user attributes from those countries).
-
-For internationalization, another field ``continents_i18n`` may be present.
-This field would be a map of language names to arrays of translated
-continent names:
-
-.. code-block:: json
-
- {
- "recovery_state": "CONTINENT_SELECTING",
- "continents": [
- "Europe",
- "North America"
- ]
- "continents_i18n":
- {
- "de_DE" : [
- "Europa",
- "Nordamerika"
- ],
- "de_CH" : [
- "Europa",
- "Nordamerika"
- ]
- }
- }
-
-Translations must be given in the same order as the main English array.
-
-
-Common transitions
-------------------
-
-**select_continent:**
-
-Here the user specifies the continent they live on. Arguments (example):
-
-.. code-block:: json
-
- {
- "continent": "Europe"
- }
-
-The continent must be given using the English name from the ``continents`` array.
-Using a translated continent name is invalid and may result in failure.
-
-The reducer returns an updated state with a list of countries to choose from,
-for example:
-
-.. code-block:: json
-
- {
- "backup_state": "COUNTRY_SELECTING",
- "selected_continent": "Europe",
- "countries": [
- {
- "code": "ch",
- "name": "Switzerland",
- "continent": "Europe",
- "name_i18n": {
- "de_DE": "Schweiz",
- "de_CH": "Schwiiz",
- "fr": "Suisse",
- "en": "Swiss"
- },
- "currency": "CHF"
- },
- {
- "code": "de",
- "name": "Germany",
- "continent": "Europe",
- "continent_i18n": {
- "de": "Europa"
- },
- "name_i18n": {
- "de_DE": "Deutschland",
- "de_CH": "Deutschland",
- "fr": "Allemagne",
- "en": "Germany"
- },
- "currency": "EUR"
- }
- ]
- }
-
-Here ``countries`` is an array of countries on the ``selected_continent``. For
-each country, the ``code`` is the ISO 3166-1 alpha-2 country code. The
-``continent`` is only present because some countries span continents, the
-information is redundant and will always match ``selected_continent``. The
-``name`` is the name of the country in English, internationalizations of the
-name may be provided in ``name_i18n``. The ``currency`` is **an** official
-currency of the country, if a country has multiple currencies, it may appear
-multiple times in the list. In this case, the user should select the entry
-with the currency they intend to pay with. It is also possible for users
-to select a currency that does not match their country, but user interfaces
-should by default try to use currencies that match the user's residence.
-
-
-**select_country:**
-
-Selects the country (via the country code) and specifies the currency.
-The latter is needed as some countries have more than one currency,
-and some use-cases may also involve users insisting on paying with
-foreign currency.
-
-Arguments (example):
-
-.. code-block:: json
-
- {
- "country_code": "de",
- "currency": "EUR"
- }
-
-The ``country_code`` must be an ISO 3166-1 alpha-2 country code from
-the array of ``countries`` of the reducer's state. The ``currency``
-field must be a valid currency accepted by the Taler payment system.
-
-The reducer returns a new state with the list of attributes the
-user is expected to provide, as well as possible authentication
-providers that accept payments in the selected currency:
-
-.. code-block:: json
-
- {
- "backup_state": "USER_ATTRIBUTES_COLLECTING",
- "selected_country": "de",
- "currency": "EUR",
- "required_attributes": [
- {
- "type": "string",
- "name": "full_name",
- "label": "Full name",
- "label_i18n": {
- "de_DE": "Vollstaendiger Name",
- "de_CH": "Vollstaendiger. Name",
- "fr": "Nom complet",
- "en": "Full name"
- },
- "widget": "anastasis_gtk_ia_full_name",
- "uuid" : "9e8f463f-575f-42cb-85f3-759559997331"
- },
- {
- "type": "date",
- "name": "birthdate",
- "label": "Birthdate",
- "label_i18n": {
- "de_DE": "Geburtsdatum",
- "de_CH": "Geburtsdatum",
- "fr": "Date de naissance",
- "en": "Birthdate"
- },
- "uuid" : "83d655c7-bdb6-484d-904e-80c1058c8854"
- "widget": "anastasis_gtk_ia_birthdate"
- },
- {
- "type": "string",
- "name": "tax_number",
- "label": "Taxpayer identification number",
- "label_i18n":{
- "de_DE": "Steuerliche Identifikationsnummer",
- "de_CH": "Steuerliche Identifikationsnummer",
- "en": "German taxpayer identification number"
- },
- "widget": "anastasis_gtk_ia_tax_de",
- "uuid": "dae48f85-e3ff-47a4-a4a3-ed981ed8c3c6",
- "validation-regex": "^[0-9]{11}$",
- "validation-logic": "DE_TIN_check"
- },
- {
- "type": "string",
- "name": "social_security_number",
- "label": "Social security number",
- "label_i18n": {
- "de_DE": "Sozialversicherungsnummer",
- "de_CH": "Sozialversicherungsnummer",
- "fr": "Numéro de sécurité sociale",
- "en": "Social security number"
- },
- "widget": "anastasis_gtk_ia_ssn",
- "validation-regex": "^[0-9]{8}[[:upper:]][0-9]{3}$",
- "validation-logic": "DE_SVN_check"
- "optional" : true
- }
- ],
- "authentication_providers": {
- "http://localhost:8089/": {
- "http_status": 200,
- "methods": [
- { "type" : "question",
- "usage_fee" : "EUR:0.0" },
- { "type" : "sms",
- "usage_fee" : "EUR:0.5" }
- ],
- "annual_fee": "EUR:4.99",
- "truth_upload_fee": "EUR:4.99",
- "liability_limit": "EUR:1",
- "currency": "EUR",
- "truth_lifetime": { "d_ms" : 50000000 },
- "storage_limit_in_megabytes": 1,
- "provider_name": "Anastasis 4",
- "salt": "CXAPCKSH9D3MYJTS9536RHJHCW"
- },
- "http://localhost:8088/": {
- "http_status": 200,
- "methods": [
- { "type" : "question",
- "usage_fee" : "EUR:0.01" },
- { "type" : "sms",
- "usage_fee" : "EUR:0.55" }
- ],
- "annual_fee": "EUR:0.99",
- "truth_upload_fee": "EUR:3.99",
- "liability_limit": "EUR:1",
- "currency": "EUR",
- "truth_lifetime": { "d_ms" : 50000000 },
- "storage_limit_in_megabytes": 1,
- "provider_name": "Anastasis 4",
- "salt": "CXAPCKSH9D3MYJTS9536RHJHCW"
- }
- }
- }
-
-The array of ``required_attributes`` contains attributes about the user
-that must be provided includes:
-
- - **type**: The type of the attribute, for now only ``string`` and ``date`` are
- supported.
- - **name**: The name of the attribute, this is the key under which the
- attribute value must be provided later. The name must be unique per response.
- - **label**: A human-readable description of the attribute in English.
- Translated descriptions may be provided under **label_i18n**.
- - **uuid**: A UUID that uniquely identifies identical attributes across
- different countries. Useful to preserve values should the user enter
- some attributes, and then switch to another country. Note that
- attributes must not be preserved if they merely have the same **name**,
- only the **uuid** will be identical if the semantics is identical.
- - **widget**: An optional name of a widget that is known to nicely render
- the attribute entry in user interfaces where named widgets are
- supported.
- - **validation-regex**: An optional extended POSIX regular expression
- that is to be used to validate (string) inputs to ensure they are
- well-formed.
- - **validation-logic**: Optional name of a function that should be called
- to validate the input. If the function is not known to the particular
- client, the respective validation can be skipped (at the expense of
- typos by users not being detected, possibly rendering secrets
- irrecoverable).
- - **optional**: Optional boolean field that, if ``true``, indicates that
- this attribute is not actually required but optional and users MAY leave
- it blank in case they do not have the requested information. Used for
- common fields that apply to some large part of the population but are
- not sufficiently universal to be actually required.
-
-The authentication providers are listed under a key that is the
-base URL of the service. For each provider, the following
-information is provided if the provider was successfully contacted:
-
- - **http_status**: HTTP status code, always ``200`` on success.
- - **methods**: Array of authentication methods supported by this
- provider. Includes the **type** of the authentication method
- and the **usage_fee** (how much the user must pay for authorization
- using this method during recovery).
- - **annual_fee**: Fee the provider charges to store the recovery
- policy for one year.
- - **truth_upload_fee**: Fee the provider charges to store a key share.
- - **liability_limit**: Amount the provider can be held liable for in
- case a key share or recovery document cannot be recovered due to
- provider failures.
- - **currency**: Currency in which the provider wants to be paid,
- will match all of the fees.
- - **storage_limit_in_megabytes**: Maximum size of an upload (for
- both recovery document and truth data) in megabytes.
- - **provider_name**: Human-readable name of the provider's business.
- - **salt**: Salt value used by the provider, used to derive the
- user's identity at this provider. Should be unique per provider,
- and must never change for a given provider. The salt is
- base32 encoded.
-
-If contacting the provider failed, the information returned is:
-
- - **http_status**: HTTP status code (if available, possibly 0 if
- we did not even obtain an HTTP response).
- - **error_code**: Taler error code, never 0.
-
-
-**add_provider**:
-
-This operation can be performed in state ``USER_ATTRIBUTES_COLLECTING``. It
-adds one or more Anastasis providers to the list of providers the reducer
-should henceforth consider. Note that removing providers is not possible at
-this time.
-
-Here, the client must provide an array with the base URLs of the
-providers to add, for example:
-
-.. code-block:: json
-
- {
- "urls": [
- "http://localhost:8888/",
- "http://localhost:8089/"
- ]
- }
-
-Note that existing providers will remain in the state. The following is an
-example for an expected new state where the service on port 8089 is
-unreachable, the service on port 8088 was previously known, and service on
-port 8888 was now added:
-
-.. code-block:: json
-
- {
- "backup_state": "USER_ATTRIBUTES_COLLECTING",
- "authentication_providers": {
- "http://localhost:8089/": {
- "error_code": 11,
- "http_status": 0
- },
- "http://localhost:8088/": {
- "http_status": 200,
- "methods": [
- { "type" : "question",
- "usage_fee" : "EUR:0.01" },
- { "type" : "sms",
- "usage_fee" : "EUR:0.55" }
- ],
- "annual_fee": "EUR:0.99",
- "truth_upload_fee": "EUR:3.99",
- "liability_limit": "EUR:1",
- "currency": "EUR",
- "truth_lifetime": { "d_ms" : 50000000 },
- "storage_limit_in_megabytes": 1,
- "provider_name": "Anastasis 4",
- "salt": "CXAPCKSH9D3MYJTS9536RHJHCW"
- }
- "http://localhost:8888/": {
- "methods": [
- { "type" : "question",
- "usage_fee" : "EUR:0.01" },
- { "type" : "sms",
- "usage_fee" : "EUR:0.55" }
- ],
- "annual_fee": "EUR:0.99",
- "truth_upload_fee": "EUR:3.99",
- "liability_limit": "EUR:1",
- "currency": "EUR",
- "truth_lifetime": { "d_ms" : 50000000 },
- "storage_limit_in_megabytes": 1,
- "provider_name": "Anastasis 42",
- "salt": "BXAPCKSH9D3MYJTS9536RHJHCX"
- }
- }
- }
-
-
-
-Backup transitions
-------------------
-
-**enter_user_attributes:**
-
-This transition provides the user's personal attributes. The specific set of
-attributes required depends on the country of residence of the user. Some
-attributes may be optional, in which case they should be omitted entirely
-(that is, not simply be set to ``null`` or an empty string). Example
-arguments would be:
-
-.. code-block:: json
-
- {
- "identity_attributes": {
- "full_name": "Max Musterman",
- "social_security_number": "123456789",
- "birthdate": "2000-01-01",
- "birthplace": "Earth"
- }
- }
-
-Note that at this stage, the state machines between backup and
-recovery diverge and the ``recovery_state`` will begin to look
-very different from the ``backup_state``.
-
-For backups, if all required attributes are present, the reducer will
-transition to an ``AUTHENTICATIONS_EDITING`` state with the attributes added
-to it:
-
-.. code-block:: json
-
- {
- "backup_state": "AUTHENTICATIONS_EDITING",
- "identity_attributes": {
- "full_name": "Max Musterman",
- "social_security_number": "123456789",
- "birthdate": "2000-01-01",
- "birthplace": "Earth"
- }
- }
-
-If required attributes are missing, do not match the required regular
-expression, or fail the custom validation logic, the reducer SHOULD transition
-to an error state indicating what was wrong about the input. A reducer that
-does not support some specific validation logic MAY accept the invalid input
-and proceed anyway. The error state will include a Taler error code that
-is specific to the failure, and optional details. Example:
-
-.. code-block:: json
-
- {
- "backup_state": "ERROR",
- "code": 8404,
- "hint": "An input did not match the regular expression.",
- "detail": "social_security_number"
- }
-
-Clients may safely repeat this transition to validate the user's inputs
-until they satisfy all of the constraints. This way, the user interface
-does not have to perform the input validation directly.
-
-
-**add_authentication**:
-
-This transition adds an authentication method. The method must be supported
-by one or more providers that are included in the current state. Adding an
-authentication method requires specifying the ``type`` and ``instructions`` to
-be given to the user. The ``challenge`` is encrypted and stored at the
-Anastasis provider. The specific semantics of the value depend on the
-``type``. Typical challenges values are a phone number (to send an SMS to),
-an e-mail address (to send a PIN code to) or the answer to a security
-question. Note that these challenge values will still be encrypted (and
-possibly hashed) before being given to the Anastasis providers.
-
-Note that the ``challenge`` must be given in Crockford Base32 encoding, as it
-MAY include binary data (such as a photograph of the user). In the latter
-case, the optional ``mime_type`` field must be provided to give the MIME type
-of the value encoded in ``challenge``.
-
-.. code-block:: json
-
- {
- "authentication_method":
- {
- "type": "question",
- "mime_type" : "text/plain",
- "instructions" : "What is your favorite GNU package?",
- "challenge" : "E1QPPS8A",
- }
- }
-
-If the information provided is valid, the reducer will add the new
-authentication method to the array of authentication methods:
-
-.. code-block:: json
-
- {
- "backup_state": "AUTHENTICATIONS_EDITING",
- "authentication_methods": [
- {
- "type": "question",
- "mime_type" : "text/plain",
- "instructions" : "What is your favorite GNU package?",
- "challenge" : "E1QPPS8A",
- },
- {
- "type": "email",
- "instructions" : "E-mail to user@*le.com",
- "challenge": "ENSPAWJ0CNW62VBGDHJJWRVFDM50"
- }
- ]
- }
-
-
-**delete_authentication**:
-
-This transition can be used to remove an authentication method from the
-array of authentication methods. It simply requires the index of the
-authentication method to remove. Note that the array is 0-indexed:
-
-.. code-block:: json
-
- {
- "authentication_method": 1
- }
-
-Assuming we begin with the state from the example above, this would
-remove the ``email`` authentication method, resulting in the following
-response:
-
-.. code-block:: json
-
- {
- "backup_state": "AUTHENTICATIONS_EDITING",
- "authentication_methods": [
- {
- "type": "question",
- "mime_type" : "text/plain",
- "instructions" : "What is your favorite GNU package?",
- "challenge" : "gdb",
- }
- ]
- }
-
-If the index is invalid, the reducer will instead
-transition into an ``ERROR`` state.
-
-
-**next** (from ``AUTHENTICATIONS_EDITING``):
-
-This transition confirms that the user has finished adding (or removing)
-authentication methods, and that the system should now automatically compute
-a set of reasonable recovery policies.
-
-This transition does not take any mandatory arguments. Optional arguments can
-be provided to upload the recovery document only to a specific subset of the
-providers:
-
-.. code-block:: json
-
- {
- "providers": [
- "http://localhost:8088/",
- "http://localhost:8089/"
- ]
- }
-
-The resulting state provides the suggested recovery policies in a way suitable
-for presentation to the user:
-
-.. code-block:: javascript
-
- {
- "backup_state": "POLICIES_REVIEWING",
- "policy_providers" : [
- { "provider_url" : "http://localhost:8088/" },
- { "provider_url" : "http://localhost:8089/" }
- ],
- "policies": [
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8088/"
- },
- {
- "authentication_method": 1,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 2,
- "provider": "http://localhost:8087/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8088/"
- },
- {
- "authentication_method": 1,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 3,
- "provider": "http://localhost:8089/"
- }
- ]
- }
- ]
- }
-
-For each recovery policy, the state includes the specific details of which
-authentication ``methods`` must be solved to recovery the secret using this
-policy. The ``methods`` array specifies the index of the
-``authentication_method`` in the ``authentication_methods`` array, as well as
-the provider that was selected to supervise this authentication.
-
-If no authentication method was provided, the reducer will transition into an
-``ERROR`` state instead of suggesting policies.
-
-
-**add_policy**:
-
-Using this transition, the user can add an additional recovery policy to the
-state. The argument format is the same that is used in the existing state.
-An example for a possible argument would thus be:
-
-.. code-block:: javascript
-
- {
- "policy": [
- {
- "authentication_method": 1,
- "provider": "http://localhost:8088/"
- },
- {
- "authentication_method": 3,
- "provider": "http://localhost:8089/"
- }
- ]
- }
-
-Note that the specified providers must already be in the
-``authentication_providers`` of the state. You cannot add new providers at
-this stage. The reducer will simply attempt to append the suggested policy to
-the "policies" array, returning an updated state:
-
-.. code-block:: json
-
- {
- "backup_state": "POLICIES_REVIEWING",
- "policies": [
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 1,
- "provider": "http://localhost:8088/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 2,
- "provider": "http://localhost:8088/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 1,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 2,
- "provider": "http://localhost:8088/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 1,
- "provider": "http://localhost:8088/"
- },
- {
- "authentication_method": 3,
- "provider": "http://localhost:8089/"
- }
- ]
- }
- ]
- }
-
-If the new policy is invalid, for example because it adds an unknown
-authentication method, or the selected provider does not support the type of
-authentication, the reducer will transition into an ``ERROR`` state instead of
-adding the new policy.
-
-
-**update_policy**:
-
-Using this transition, the user can modify an existing recovery policy
-in the state.
-The argument format is the same that is used in **add_policy**,
-except there is an additional key ``policy_index`` which
-identifies the policy to modify.
-An example for a possible argument would thus be:
-
-.. code-block:: javascript
-
- {
- "policy_index" : 1,
- "policy": [
- {
- "authentication_method": 1,
- "provider": "http://localhost:8088/"
- },
- {
- "authentication_method": 3,
- "provider": "http://localhost:8089/"
- }
- ]
- }
-
-If the new policy is invalid, for example because it adds an unknown
-authentication method, or the selected provider does not support the type of
-authentication, the reducer will transition into an ``ERROR`` state instead of
-modifying the policy.
-
-
-
-**delete_policy:**
-
-This transition allows the deletion of a recovery policy. The argument
-simply specifies the index of the policy to delete, for example:
-
-.. code-block:: json
-
- {
- "policy_index": 3
- }
-
-Given as input the state from the example above, the expected new state would
-be:
-
-.. code-block:: json
-
- {
- "backup_state": "POLICIES_REVIEWING",
- "policies": [
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 1,
- "provider": "http://localhost:8088/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 2,
- "provider": "http://localhost:8088/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 1,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 2,
- "provider": "http://localhost:8088/"
- }
- ]
- }
- ]
- }
-
-If the index given is invalid, the reducer will transition into an ``ERROR`` state
-instead of deleting a policy.
-
-
-**delete_challenge:**
-
-This transition allows the deletion of an individual
-challenge from a recovery policy. The argument
-simply specifies the index of the policy and challenge
-to delete, for example:
-
-.. code-block:: json
-
- {
- "policy_index": 1,
- "challenge_index" : 1
- }
-
-Given as input the state from the example above, the expected new state would
-be:
-
-.. code-block:: json
-
- {
- "backup_state": "POLICIES_REVIEWING",
- "policies": [
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 1,
- "provider": "http://localhost:8088/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 0,
- "provider": "http://localhost:8089/"
- }
- ]
- },
- {
- "methods": [
- {
- "authentication_method": 1,
- "provider": "http://localhost:8089/"
- },
- {
- "authentication_method": 2,
- "provider": "http://localhost:8088/"
- }
- ]
- }
- ]
- }
-
-If the index given is invalid, the reducer will transition into an ``ERROR`` state
-instead of deleting a challenge.
-
-
-**next** (from ``POLICIES_REVIEWING``):
-
-Using this transition, the user confirms that the policies in the current
-state are acceptable. The transition does not take any arguments.
-
-The reducer will simply transition to the ``SECRET_EDITING`` state:
-
-.. code-block:: json
-
- {
- "backup_state": "SECRET_EDITING",
- "upload_fees" : [ "KUDOS:42" ],
- "expiration" : { "t_ms" : 1245362362 }
- }
-
-Here, ``upload_fees`` is an array of applicable upload fees for the
-given policy expiration time. This is an array because fees could
-be in different currencies. The final cost may be lower if the
-user already paid for some of the time.
-
-If the array of ``policies`` is currently empty, the reducer will transition
-into an ``ERROR`` state instead of allowing the user to continue.
-
-
-**enter_secret:**
-
-This transition provides the reducer with the actual core ``secret`` of the user
-that Anastasis is supposed to backup (and possibly recover). The argument is
-simply the Crockford-Base32 encoded ``value`` together with its ``mime`` type, or a ``text`` field with a human-readable secret text.
-For example:
-
-.. code-block:: javascript
-
- {
- "secret": {
- "value": "EDJP6WK5EG50",
- "mime" : "text/plain"
- },
- "expiration" : { "t_ms" : 1245362362 }
- }
-
-If the application is unaware of the format, it set the ``mime`` field to ``null``.
-The ``expiration`` field is optional.
-
-The reducer remains in the ``SECRET_EDITING`` state, but now the secret and
-updated expiration time are part of the state and the cost calculations will
-be updated.
-
-.. code-block:: json
-
- {
- "backup_state": "SECRET_EDITING",
- "core_secret" : {
- "value": "EDJP6WK5EG50",
- "mime" : "text/plain"
- },
- "expiration" : { "t_ms" : 1245362362 },
- "upload_fees" : [ "KUDOS:42" ]
- }
-
-
-**clear_secret:**
-
-This transition removes the core secret from the state. It is simply a
-convenience function to undo ``enter_secret`` without providing a new value
-immediately. The transition takes no arguments. The resuting state will no
-longer have the ``core_secret`` field, and be otherwise unchanged. Calling
-**clear_secret** on a state without a ``core_secret`` will result in an error.
-
-
-**enter_secret_name:**
-
-This transition provides the reducer with a name for the core ``secret`` of the user. This name will be given to the user as a hint when seleting a recovery policy document during recovery, prior to satisfying any of the challenges. The argument simply contains the name for the secret.
-Applications that have build-in support for Anastasis MUST prefix the
-secret name with an underscore and an application-specific identifier
-registered in GANA so that they can use recognize their own backups.
-An example argument would be:
-
-.. code-block:: javascript
-
- {
- "name": "_TALERWALLET_MyPinePhone",
- }
-
-Here, ``MyPinePhone`` might be chosen by the user to identify the
-device that was being backed up.
-
-The reducer remains in the ``SECRET_EDITING`` state, but now the
-secret name is updated:
-
-.. code-block:: json
-
- {
- "secret_name" : "_TALERWALLET_MyPinePhone"
- }
-
-
-**update_expiration:**
-
-This transition asks the reducer to change the desired expiration time
-and to update the associated cost. For example:
-
-.. code-block:: javascript
-
- {
- "expiration" : { "t_ms" : 1245362362 }
- }
-
-The reducer remains in the ``SECRET_EDITING`` state, but the
-expiration time and cost calculation will be updated.
-
-.. code-block:: json
-
- {
- "backup_state": "SECRET_EDITING",
- "expiration" : { "t_ms" : 1245362362 },
- "upload_fees" : [ { "fee": "KUDOS:43" } ]
- }
-
-
-**next** (from ``SECRET_EDITING``):
-
-Using this transition, the user confirms that the secret and expiration
-settings in the current state are acceptable. The transition does not take any
-arguments.
-
-If the secret is currently empty, the reducer will transition into an
-``ERROR`` state instead of allowing the user to continue.
-
-After adding a secret, the reducer may transition into different states
-depending on whether payment(s) are necessary. If payments are needed, the
-``secret`` will be stored in the state under ``core_secret``. Applications
-should be careful when persisting the resulting state, as the ``core_secret``
-is not protected in the ``PAYING`` states. The ``PAYING`` states only differ
-in terms of what the payments are for (key shares or the recovery document),
-in all cases the state simply includes an array of Taler URIs that refer to
-payments that need to be made with the Taler wallet.
-
-If all payments are complete, the reducer will transition into the
-``BACKUP_FINISHED`` state and (if applicable) delete the ``core_secret`` as an
-additional safety measure.
-
-Example results are thus:
-
-.. code-block:: json
-
- {
- "backup_state": "TRUTHS_PAYING",
- "secret_name" : "$NAME",
- "core_secret" : { "$anything":"$anything" },
- "payments": [
- "taler://pay/...",
- "taler://pay/..."
- ]
- }
-
-.. code-block:: json
-
- {
- "backup_state": "POLICIES_PAYING",
- "secret_name" : "$NAME",
- "core_secret" : { "$anything":"$anything" },
- "payments": [
- "taler://pay/...",
- "taler://pay/..."
- ]
- }
-
-.. code-block:: json
-
- {
- "backup_state": "BACKUP_FINISHED",
- }
-
-
-**pay:**
-
-This transition suggests to the reducer that a payment may have been made or
-is immanent, and that the reducer should check with the Anastasis service
-provider to see if the operation is now possible. The operation takes one
-optional argument, which is a ``timeout`` value that specifies how long the
-reducer may wait (in long polling) for the payment to complete:
-
-.. code-block:: json
-
- {
- "timeout": { "d_ms" : 5000 },
- }
-
-The specified timeout is passed on to the Anastasis service provider(s), which
-will wait this long before giving up. If no timeout is given, the check is
-done as quickly as possible without additional delays. The reducer will continue
-to either an updated state with the remaining payment requests, to the
-``BACKUP_FINISHED`` state (if all payments have been completed and the backup
-finished), or into an ``ERROR`` state in case there was an irrecoverable error,
-indicating the specific provider and how it failed. An example for this
-final error state would be:
-
-.. code-block:: json
-
- {
- "backup_state": "ERROR",
- "http_status" : 500,
- "upload_status" : 52,
- "provider_url" : "https://bad.example.com/",
- }
-
-Here, the fields have the following meaning:
-
- - **http_status** is the HTTP status returned by the Anastasis provider.
- - **upload_status** is the Taler error code return by the provider.
- - **provider_url** is the base URL of the failing provider.
-
-In the above example, 52 would thus imply that the Anastasis provider failed to
-store information into its database.
-
-
-Recovery transitions
---------------------
-
-**enter_user_attributes:**
-
-This transition provides the user's personal attributes. The specific set of
-attributes required depends on the country of residence of the user. Some
-attributes may be optional, in which case they should be omitted entirely
-(that is, not simply be set to ``null`` or an empty string). The
-arguments are identical to the **enter_user_attributes** transition from
-the backup process. Example arguments would thus be:
-
-.. code-block:: json
-
- {
- "identity_attributes": {
- "full_name": "Max Musterman",
- "social_security_number": "123456789",
- "birthdate": "2000-01-01",
- "birthplace": "Earth"
- }
- }
-
-However, in contrast to the backup process, the reducer will attempt to
-retrieve the latest recovery document from all known providers for the
-selected currency given the above inputs. If a recovery document was found
-by any provider, the reducer will attempt to load it and transition to
-a state where the user can choose which challenges to satisfy:
-
-.. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "challenges": [
- {
- "uuid": "MW2R3RCBZPHNC78AW8AKWRCHF9KV3Y82EN62T831ZP54S3K5599G",
- "cost": "TESTKUDOS:0",
- "type": "question",
- "instructions": "q1"
- },
- {
- "uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "cost": "TESTKUDOS:0",
- "type": "email",
- "instructions": "e-mail address m?il@f*.bar"
- },
- ],
- "policies": [
- [
- {
- "uuid": "MW2R3RCBZPHNC78AW8AKWRCHF9KV3Y82EN62T831ZP54S3K5599G"
- },
- {
- "uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0"
- },
- ],
- ],
- "provider_url": "http://localhost:8088/",
- "version": 1,
- },
- "recovery_document": {
- "...": "..."
- }
- }
-
-The ``recovery_document`` is an internal representation of the recovery
-information and of no concern to the user interface. The pertinent information
-is in the ``recovery_information``. Here, the ``challenges`` array is a list
-of possible challenges the user could attempt to solve next, while ``policies``
-is an array of policies, with each policy being an array of challenges.
-Satisfying all of the challenges of one of the policies will enable the secret
-to be recovered. The ``provider_url`` from where the recovery document was
-obtained and its ``version`` are also provided. Each challenge comes with
-four mandatory fields:
-
- - **uuid**: A unique identifier of the challenge; this is what the
- UUIDs in the policies array refer to, but also this UUID may be
- included in messages sent to the user. They allow the user to
- distinguish different PIN/TANs should say the same phone number be
- used for SMS-authentication with different providers.
- - **cost**: This is the amount the Anastasis provider will charge
- to allow the user to pass the challenge.
- - **type**: This is the type of the challenge, as a string.
- - **instructions**: Contains additional important hints for the user
- to allow the user to satisfy the challenge. It typically includes
- an abbreviated form of the contact information or the security
- question. Details depend on ``type``.
-
-If a recovery document was not found, either the user never performed
-a backup, entered incorrect attributes, or used a provider not yet in
-the list of Anastasis providers. Hence, the user must now either
-select a different provider, or go ``back`` and update the identity
-attributes. In the case a recovery document was not found, the
-transition fails, returning the error code and a human-readable error
-message together with a transition failure:
-
-.. code-block:: json
-
- {
- "recovery_state": "ERROR",
- "error_message": "account unknown to Anastasis server",
- "error_code": 9,
- }
-
-Here, the ``error_code`` is from the ``enum ANASTASIS_RecoveryStatus``
-and describes precisely what failed about the download, while the
-``error_message`` is a human-readable (English) explanation of the code.
-Applications may want to translate the message using GNU gettext;
-translations should be available in the ``anastasis`` text domain.
-However, in general it should be sufficient to display the slightly
-more generic Taler error code that is returned with the new state.
-
-
-**change_version:**
-
-Even if a recovery document was found, it is possible that the user
-intended to recover a different version, or recover a backup where
-the recovery document is stored at a different provider. Thus, the
-reducer allows the user to explicitly switch to a different provider
-or recovery document version using the ``change_version`` transition,
-which takes a provider URL and policy version as arguments:
-
-.. code-block:: json
-
- {
- "provider_url": "https://localhost:8080/",
- "version": 2
- }
-
-Note that using a version of 0 implies fetching "the latest version". The
-resulting states are the same as those of the ``enter_user_attributes``
-transition, except that the recovery document version is not necessarily the
-latest available version at the provider.
-
-
-**select_challenge:**
-
-Selecting a challenge takes different, depending on the state of the payment.
-A comprehensive example for ``select_challenge`` would be:
-
-.. code-block:: json
-
- {
- "uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30"
- "timeout" : { "d_ms" : 5000 },
- "payment_secret": "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
- }
-
-The ``uuid`` field is mandatory and specifies the selected challenge.
-The other fields are optional, and are needed in case the user has
-previously been requested to pay for the challenge. In this case,
-the ``payment_secret`` identifies the previous payment request, and
-``timeout`` says how long the Anastasis service should wait for the
-payment to be completed before giving up (long polling).
-
-Depending on the type of the challenge and the need for payment, the
-reducer may transition into ``CHALLENGE_SOLVING`` or ``CHALLENGE_PAYING``
-states. In ``CHALLENGE_SOLVING``, the new state will primarily specify
-the selected challenge:
-
-.. code-block:: json
-
- {
- "backup_state": "CHALLENGE_SOLVING",
- "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30"
- }
-
-In ``CHALLENGE_PAYING``, the new state will include instructions for payment
-in the ``challenge_feedback``. In general, ``challenge_feedback`` includes
-information about attempted challenges, with the final state being ``solved``:
-
-.. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "challenge_feedback": {
- "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : {
- "state" : "solved"
- }
- }
- }
-
-Challenges feedback for a challenge can have many different ``state`` values
-that applications must all handle. States other than ``solved`` are:
-
- - **payment**: Here, the user must pay for a challenge. An example would be:
-
- .. code-block:: json
-
- {
- "backup_state": "CHALLENGE_PAYING",
- "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30",
- "challenge_feedback": {
- "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : {
- "state" : "payment",
- "taler_pay_uri" : "taler://pay/...",
- "provider" : "https://localhost:8080/",
- "payment_secret" : "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
- }
- }
- }
-
- - **body**: Here, the server provided an HTTP reply for
- how to solve the challenge, but the reducer could not parse
- them into a known format. A mime-type may be provided and may
- help parse the details.
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "body",
- "body": "CROCKFORDBASE32ENCODEDBODY",
- "http_status": 403,
- "mime_type" : "anything/possible"
- }
- }
- }
-
- - **hint**: Here, the server provided human-readable hint for
- how to solve the challenge. Note that the ``hint`` provided this
- time is from the Anastasis provider and may differ from the ``instructions``
- for the challenge under ``recovery_information``:
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "hint",
- "hint": "Recovery TAN send to email mail@DOMAIN",
- "http_status": 403
- }
- }
- }
-
- - **details**: Here, the server provided a detailed JSON status response
- related to solving the challenge:
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "details",
- "details": {
- "code": 8111,
- "hint": "The client's response to the challenge was invalid.",
- "detail" : null
- },
- "http_status": 403
- }
- }
- }
-
- - **redirect**: To solve the challenge, the user must visit the indicated
- Web site at ``redirect_url``, for example to perform video authentication:
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SOLVING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "redirect",
- "redirect_url": "https://videoconf.example.com/",
- "http_status": 303
- }
- }
- }
-
- - **server-failure**: This indicates that the Anastasis provider encountered
- a failure and recovery using this challenge cannot proceed at this time.
- Examples for failures might be that the provider is unable to send SMS
- messages at this time due to an outage. The body includes details about
- the failure. The user may try again later or continue with other challenges.
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "server-failure",
- "http_status": "500",
- "error_code": 52
- }
- }
- }
-
- - **truth-unknown**: This indicates that the Anastasis provider is unaware of
- the specified challenge. This is typically a permanent failure, and user
- interfaces should not allow users to re-try this challenge.
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "truth-unknown",
- "error_code": 8108
- }
- }
- }
-
- - **rate-limit-exceeded**:
-
- .. code-block:: json
-
- {
- "recovery_state": "CHALLENGE_SELECTING",
- "recovery_information": {
- "...": "..."
- }
- "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
- "challenge_feedback": {
- "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": {
- "state": "rate-limit-exceeded",
- "error_code": 8121
- }
- }
- }
-
-**pay:**
-
-With a ``pay`` transition, the application indicates to the reducer that
-a payment may have been made. Here, it is again possible to specify an
-optional ``timeout`` argument for long-polling, for example:
-
-.. code-block:: json
-
- {
- "payment_secret": "ABCDADF242525AABASD52525235ABABFDABABANALASDAAKASDAS"
- "timeout" : { "d_ms" : 5000 },
- }
-
-Depending on the type of the challenge and the result of the operation, the
-new state may be ``CHALLENGE_SOLVING`` (if say the SMS was now sent to the
-user), ``CHALLENGE_SELECTING`` (if the answer to the security question was
-correct), ``RECOVERY_FINISHED`` (if this was the last challenge that needed to
-be solved) or still ``CHALLENGE_PAYING`` (if the challenge was not actually
-paid for). For sample messages, see the different types of
-``challenge_feedback`` in the section about ``select_challenge``.
-
-
-**solve_challenge:**
-
-Solving a challenge takes various formats, depending on the type of the
-challenge and what is known about the answer. The different supported
-formats are:
-
-.. code-block:: json
-
- {
- "answer": "answer to security question"
- }
-
-.. code-block:: json
-
- {
- "pin": 1234
- }
-
-.. code-block:: json
-
- {
- "hash": "SOMEBASE32ENCODEDHASHVALUE"
- }
-
-
-.. _anastasis-auth-methods:
-
-----------------------
-Authentication Methods
-----------------------
-
-This section describes the supported authentication methods in detail. We
-note that the server implements rate limiting for all authentication methods
-to ensure that malicious strong attackers cannot guess the values by
-brute-force. Typically, a user is given three attempts per hour to enter the
-correct code from 2^63 possible values. Transmitted codes also come with an
-expiration date. If the user re-requests a challenge to be sent, the same
-challenge may be transmitted (with the three attempts counter not increasing!)
-for a limited period of time (depending on the authentication method) before
-the service eventually rotates to a fresh random code with a fresh retry
-counter. Given the default value range and time intervals (which providers are
-at liberty to adjust), brute-force attacks against this are expected to
-succeed with a 50% probability after about 200000 years of attempts at the
-maximum permissible frequency.
-
-
-SMS (sms)
-^^^^^^^^^
-
-Sends an SMS with a code (prefixed with ``A-``) to the user's phone, including
-a UUID which identifies the challenge the code is for. The user must send
-this code back with his request (see ``$RESPONSE`` under `Managing truth`_).
-If the transmitted code is correct, the server responses with the requested
-encrypted key share.
-
-
-
-Email verification (email)
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Sends an email with a code (prefixed with ``A-``) to the user's mail address,
-including a UUID which identifies the challenge the code is for. The user
-must send this code back with his request (see ``$RESPONSE`` under `Managing
-truth`_). If the transmitted code is correct, the server responses with the
-requested encrypted key share.
-
-
-Video identification (vid)
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Requires the user to identify via video-call. In the video-call, the
-user is told the code (prefixed with ``A-``) needed to authenticate.
-
-The user is expected to delete all metadata revealing personal information
-from the images before uploading them. Since the respective images must be
-passed on to the video identification service in the event of password
-recovery, it should be ensured that no further information about the user can
-be derived from them.
-
-Video identification will typically result in the Anastasis provider
-requesting the user to be redirected to a Web site (or other URL) for the
-video-call.
-
-
-
-Security question (qa)
-^^^^^^^^^^^^^^^^^^^^^^
-
-Asks the user a security question. The user sends back a **salted**
-hash over the answer. The **question-salt** is stored encrypted as
-part of the recovery document and never revealed to the providers. This
-ensures that providers cannot derive the answer from the hash value.
-Furthermore, the security question itself is also only in the recovery
-document and never given to the Anastasis provider. A moderately expensive
-hash function is used to further limit strong attackers that have obtained
-the recovery document from brute-forcing the answer.
-
-If the hash value matches with the one the server is expecting, the server
-answers with the requested encrypted key share. However, unlike other
-encrypted key shares, the encrypted key share of a security question uses a
-special variation of the Anastasis encryption: Here, a different hash function
-over the security answer is used to provide an additional **key-salt** for the
-decryption of the (encrypted) **key share**. This ensures that the key share
-remains irrecoverable without the answer even if the Anastasis provider
-storing the security question is malicious.
-
-
-Snail mail verification (post)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Sends physical mail (snail mail) with a code (prefixed with ``A-``) to the
-user's mail address, including a UUID which identifies the challenge the code
-is for. The user must send this code back with their request (see
-``$RESPONSE`` under `Managing truth`_). If the transmitted code is correct,
-the server responds with the requested encrypted key share.
-
-
--------------------
-Anastasis DB Schema
--------------------
-.. image:: anastasis-db.png
-.. image:: anastasis_challengecode.png
-.. image:: anastasis_challenge_payment.png
-.. image:: anastasis_truth.png
-.. image:: anastasis_truth_payment.png