summaryrefslogtreecommitdiff
path: root/texinfo/anastasis.texi
diff options
context:
space:
mode:
Diffstat (limited to 'texinfo/anastasis.texi')
-rw-r--r--texinfo/anastasis.texi2792
1 files changed, 2792 insertions, 0 deletions
diff --git a/texinfo/anastasis.texi b/texinfo/anastasis.texi
new file mode 100644
index 00000000..cd9938f2
--- /dev/null
+++ b/texinfo/anastasis.texi
@@ -0,0 +1,2792 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename anastasis.info
+@documentencoding UTF-8
+@ifinfo
+@*Generated by Sphinx 3.4.3.@*
+@end ifinfo
+@settitle Anastasis Manual
+@defindex ge
+@paragraphindent 0
+@exampleindent 4
+@finalout
+@dircategory CATEGORY
+@direntry
+* MENU ENTRY: (anastasis.info). DESCRIPTION
+@end direntry
+
+@definfoenclose strong,`,'
+@definfoenclose emph,`,'
+@c %**end of header
+
+@copying
+@quotation
+GNU Taler 0.8.0pre0, Apr 26, 2021
+
+Anastasis team
+
+Copyright @copyright{} 2014-2021 Taler Systems SA (GPLv3+ or GFDL 1.3+)
+@end quotation
+
+@end copying
+
+@titlepage
+@title Anastasis Manual
+@insertcopying
+@end titlepage
+@contents
+
+@c %** start of user preamble
+
+@c %** end of user preamble
+
+@ifnottex
+@node Top
+@top Anastasis Manual
+@insertcopying
+@end ifnottex
+
+@c %**start of body
+@anchor{anastasis doc}@anchor{0}
+@c This file is part of Anastasis
+@c Copyright (C) 2019. 2021 Anastasis SARL
+@c
+@c Anastasis is free software; you can redistribute it and/or modify it under the
+@c terms of the GNU General Public License as published by the Free Software
+@c Foundation; either version 2.1, or (at your option) any later version.
+@c
+@c Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
+@c WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+@c A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+@c
+@c You should have received a copy of the GNU Lesser General Public License along with
+@c Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+@c
+@c @author Christian Grothoff
+@c @author Dominik Meister
+@c @author Dennis Neufeld
+
+Anastasis is a service that allows the user to securely deposit a
+@strong{core secret} with an open set of escrow providers and recover it if the secret is
+lost. The @strong{core secret} itself is protected from the escrow providers by
+encrypting it with a @strong{master key}. The main objective of Anastasis is to
+ensure that the user can reliably recover the @strong{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" @strong{identifier} is used. This
+identifier should be difficult to guess for anybody but the user. However, the
+@strong{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 @strong{identifier}, and strong
+adversaries which somehow do know a user's @strong{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
+@strong{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 @strong{recovery document} includes all of the information a user needs to
+recover access to their core secret. It specifies a set of @strong{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 @strong{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 @strong{recovery document} also specifies @strong{policies}, which
+describe the combination(s) of the escrow methods that suffice to obtain
+access to the core secret. For example, a @strong{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
+@strong{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 @strong{recovery document} (except for its length, which
+may be exposed to an adversary which monitors the user's network traffic).
+
+@menu
+* Anastasis DB Schema::
+* Anastasis Cryptography::
+* Anastasis REST API::
+* Anastasis Reducer API::
+* Authentication Methods::
+
+@end menu
+
+@node Anastasis DB Schema,Anastasis Cryptography,Top,Top
+@anchor{anastasis anastasis}@anchor{1}@anchor{anastasis anastasis-db-schema}@anchor{2}
+@chapter Anastasis DB Schema
+
+
+@image{anastasis-figures/anastasis-db,,,,png}
+
+@image{anastasis-figures/anastasis_challengecode,,,,png}
+
+@image{anastasis-figures/anastasis_challenge_payment,,,,png}
+
+@image{anastasis-figures/anastasis_truth,,,,png}
+
+@image{anastasis-figures/anastasis_truth_payment,,,,png}
+
+@node Anastasis Cryptography,Anastasis REST API,Anastasis DB Schema,Top
+@anchor{anastasis anastasis-cryptography}@anchor{3}
+@chapter 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 @strong{identifier} using
+different HKDFs. These HKDFs are salted using the respective escrow
+provider's @strong{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 @strong{account key} to identify the account of
+the user. The account private key is derived from the user's @strong{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
+@code{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 @strong{identifier} and a high-entropy @strong{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 @strong{core secret} of the user is (AES) encrypted using a symmetric @strong{master
+key}. Recovering this master key requires the user to satisfy a particular
+@strong{policy}. Policies specify a set of @strong{escrow methods}, each of which leads
+the user to a @strong{key share}. Combining those key shares (by hashing) allows
+the user to obtain a @strong{policy key}, which can be used to decrypt the @strong{master
+key}. There can be many policies, satisfying any of these will allow the
+user to recover the master key. A @strong{recovery document} contains the
+encrypted @strong{core secret}, a set of escrow methods and a set of policies.
+
+@menu
+* Key derivations::
+* Key Usage::
+* Availability Considerations::
+
+@end menu
+
+@node Key derivations,Key Usage,,Anastasis Cryptography
+@anchor{anastasis key-derivations}@anchor{4}
+@section 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
+@strong{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 @strong{identifier}.
+
+This identifier will be first hashed with Argon2, to provide a @strong{kdf_id}
+which will be used to derive other keys later. The Hash must also include the
+respective @strong{server_salt}. This also ensures that the @strong{kdf_id} is different
+on each server. The use of Argon2 and the respective @strong{server_salt} is intended
+to make it difficult to brute-force @strong{kdf_id} values and help protect the user's
+privacy. Also this ensures that the @strong{kdf_id}s on every server differs. However,
+we do not assume that the @strong{identifier} or the @strong{kdf_id} cannot be
+determined by an adversary performing a targeted attack, as a user's
+@strong{identifier} is likely to always be known to state actors and may
+likely also be available to other actors.
+
+@example
+kdf_id := Argon2( identifier, server_salt, keysize )
+@end example
+
+@strong{identifier}: The secret defined from the user beforehand.
+
+@strong{server_salt}: The salt from the Server.
+
+@strong{keysize}: The desired output size of the KDF, here 32 bytes.
+
+@menu
+* Verification::
+* Encryption::
+
+@end menu
+
+@node Verification,Encryption,,Key derivations
+@anchor{anastasis verification}@anchor{5}
+@subsection 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 @strong{kdf_id}, decrypt) the user's policy (but
+not the core secret), or upload a new version of the
+@strong{encrypted recovery document} (but not delete an existing version).
+
+For the generation of the private key we use the @strong{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
+@strong{kdf_id}.
+
+@example
+ver_secret := HKDF(kdf_id, "ver", keysize)
+eddsa_priv := eddsa_d_to_a(ver_secret)
+eddsa_pub := get_EdDSA_Pub(eddsa_priv)
+@end example
+
+@strong{HKDF()}: The HKDF-function uses two phases: First we use HMAC-SHA512 for the extraction phase, then HMAC-SHA256 is used for expansion phase.
+
+@strong{kdf_id}: Hashed identifier.
+
+@strong{key_size}: Size of the output, here 32 bytes.
+
+@strong{ver_secret}: Derived key from the @code{kdf_id}, serves as intermediate step for the generation of the private key.
+
+@strong{eddsa_d_to_a()}: Function which converts the ver_key to a valid EdDSA private key. Specifically, assuming the value @code{eddsa_priv} is in a 32-byte array "digest", the function clears and sets certain bits as follows:
+
+@example
+digest[0] = (digest[0] & 0x7f) | 0x40;
+digest[31] &= 0xf8;
+@end example
+
+@strong{eddsa_priv}: The generated EdDSA private key.
+
+@strong{eddsa_pub}: The generated EdDSA public key.
+
+@node Encryption,,Verification,Key derivations
+@anchor{anastasis encryption}@anchor{6}
+@subsection 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 @code{nonce} and the @code{kdf_id}.
+
+@example
+(iv,key) := HKDF(kdf_id, nonce, keysize + ivsize)
+@end example
+
+@strong{HKDF()}: The HKDF-function uses two phases: First we use HMAC-SHA512 for the extraction phase, then HMAC-SHA256 is used for expansion phase.
+
+@strong{kdf_id}: Hashed identifier.
+
+@strong{keysize}: Size of the AES symmetric key, here 32 bytes.
+
+@strong{ivsize}: Size of the AES GCM IV, here 12 bytes.
+
+@strong{prekey}: Original key material.
+
+@strong{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).
+
+@strong{key}: Symmetric key which is later used to encrypt the documents with AES256-GCM.
+
+@strong{iv}: IV which will be used for AES-GCM.
+
+@node Key Usage,Availability Considerations,Key derivations,Anastasis Cryptography
+@anchor{anastasis key-usage}@anchor{7}
+@section Key Usage
+
+
+The keys we have generated are then used to encrypt the @strong{recovery document} and
+the @strong{key_share} of the user.
+
+@menu
+* Encryption: Encryption<2>.
+* Signatures::
+
+@end menu
+
+@node Encryption<2>,Signatures,,Key Usage
+@anchor{anastasis id1}@anchor{8}
+@subsection 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 @strong{recovery document} and
+the @strong{key_share}. To ensure that the key derivation for the encryption
+of the @strong{recovery document} differs fundamentally from that of an
+individual @strong{key share}, we use different salts ("erd" and "eks", respectively).
+
+@example
+(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)
+@end example
+
+@strong{encrypted_recovery_document}: The encrypted @strong{recovery document} which contains the escrow methods, policies
+and the encrypted @strong{core secret}.
+
+@strong{nonce0}: Nonce which is used to generate @emph{key0} and @emph{iv0} which are used for the encryption of the @emph{recovery document}.
+Nonce must contain the string "ERD".
+
+@strong{optional data}: Key material that optionally is contributed from the authentication method to further obfuscate the key share from the escrow provider.
+
+@strong{encrypted_key_share_i}: The encrypted @strong{key_share} which the escrow provider must release upon successful authentication.
+Here, @strong{i} must be a positive number used to iterate over the various @strong{key shares} used for the various @strong{escrow methods}
+at the various providers.
+
+@strong{nonce_i}: Nonce which is used to generate @emph{key_i} and @emph{iv_i} which are used for the encryption of the @strong{key share}. @strong{i} must be
+the same number as specified above for @emph{encrypted_key_share_i}. Nonce must contain the string "EKS" plus the according @emph{i}.
+
+As a special rule, when a @strong{security question} is used to authorize access to an
+@strong{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:
+
+@example
+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)
+@end example
+
+@strong{qsalt}: Salt value used to hash answer to satisfy the challenge to prevent the provider from determining the answer via guessing.
+
+@strong{answer}: Answer to the security question, in UTF-8, as entered by the user.
+
+@strong{powh}: Result of the (expensive, proof-of-work) hash algorithm.
+
+@strong{uuid}: UUID of the challenge associated with the security question and the encrypted key share.
+
+@strong{ekss}: Replacement salt to be used instead of "eks" when deriving the key to encrypt/decrypt the key share.
+
+@node Signatures,,Encryption<2>,Key Usage
+@anchor{anastasis signatures}@anchor{9}
+@subsection 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 @strong{Anastasis-Policy-Signature}.
+
+@example
+(anastasis-account-signature) := eddsa_sign(h_body, eddsa_priv)
+ver_res := eddsa_verifiy(h_body, anastasis-account-signature, eddsa_pub)
+@end example
+
+@strong{anastasis-account-signature}: Signature over the SHA-512 hash of the body using the purpose code @code{TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD} (1400) (see GNUnet EdDSA signature API for the use of purpose).
+
+@strong{h_body}: The hashed body.
+
+@strong{ver_res}: A boolean value. True: Signature verification passed, False: Signature verification failed.
+
+When requesting policy downloads, the client must also provide a signature:
+
+@example
+(anastasis-account-signature) := eddsa_sign(version, eddsa_priv)
+ver_res := eddsa_verifiy(version, anastasis-account-signature, eddsa_pub)
+@end example
+
+@strong{anastasis-account-signature}: Signature over the SHA-512 hash of the body using the purpose code @code{TALER_SIGNATURE_ANASTASIS_POLICY_DOWNLOAD} (1401) (see GNUnet EdDSA signature API for the use of purpose).
+
+@strong{version}: The version requested as a 64-bit integer, 2^64-1 for the "latest version".
+
+@strong{ver_res}: A boolean value. True: Signature verification passed, False: Signature verification failed.
+
+@node Availability Considerations,,Key Usage,Anastasis Cryptography
+@anchor{anastasis availability-considerations}@anchor{a}
+@section 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 @strong{payment identifier} from a payment
+made by the user. Thus, a policy upload requires both knowledge of the
+@strong{identity} and making a payment. This effectively prevents an adversary
+from using the append-only policy storage from exhausting Anastasis server
+capacity.
+
+@node Anastasis REST API,Anastasis Reducer API,Anastasis Cryptography,Top
+@anchor{anastasis anastasis-rest-api}@anchor{b}
+@chapter Anastasis REST API
+
+@anchor{anastasis salt}@anchor{c}
+@menu
+* Receiving Configuration::
+* Receiving Terms of Service::
+* Manage policy::
+* Managing truth::
+
+@end menu
+
+@node Receiving Configuration,Receiving Terms of Service,,Anastasis REST API
+@anchor{anastasis config}@anchor{d}@anchor{anastasis receiving-configuration}@anchor{e}
+@section Receiving Configuration
+
+
+@anchor{anastasis get--config}@anchor{f}
+@deffn {HTTP Get} GET /config
+
+Obtain the configuration details of the escrow provider.
+
+@strong{Response:}
+
+Returns an @ref{10,,EscrowConfigurationResponse}.
+@anchor{anastasis escrowconfigurationresponse}@anchor{10}
+@example
+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;
+
+ // How long until the service expires deposited truth
+ // (unless refreshed via another POST)?
+ truth_lifetime: RelativeTime;
+
+ // 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;
+
+@}
+@end example
+@anchor{anastasis authorizationmethodconfig}@anchor{11}
+@example
+interface AuthorizationMethodConfig @{
+ // Name of the authorization method.
+ type: string;
+
+ // Fee for accessing key share using this method.
+ cost: Amount;
+
+@}
+@end example
+@end deffn
+
+@node Receiving Terms of Service,Manage policy,Receiving Configuration,Anastasis REST API
+@anchor{anastasis receiving-terms-of-service}@anchor{12}@anchor{anastasis terms}@anchor{13}
+@section Receiving Terms of Service
+
+
+@anchor{anastasis get--terms}@anchor{14}
+@deffn {HTTP Get} GET /terms
+
+Obtain the terms of service provided by the escrow provider.
+
+@strong{Response:}
+
+Returns the terms of service of the provider, in the best language
+and format available based on the client's request.
+@end deffn
+
+@anchor{anastasis get--privacy}@anchor{15}
+@deffn {HTTP Get} GET /privacy
+
+Obtain the privacy policy of the service provided by the escrow provider.
+
+@strong{Response:}
+
+Returns the privacy policy of the provider, in the best language
+and format available based on the client's request.
+@end deffn
+
+@node Manage policy,Managing truth,Receiving Terms of Service,Anastasis REST API
+@anchor{anastasis id2}@anchor{16}@anchor{anastasis manage-policy}@anchor{17}
+@section 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 @code{$ACCOUNT_PUB}, which
+should be kept secret from third parties. @code{$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@footnote{https://tools.ietf.org/html/rfc4122}.
+
+@anchor{anastasis get--policy-$ACCOUNT_PUB[?version=$NUMBER]}@anchor{18}
+@deffn {HTTP Get} GET /policy/$ACCOUNT_PUB[?version=$NUMBER]
+
+Get the customer's encrypted recovery document. If @code{version}
+is not specified, the server returns the latest available version. If
+@code{version} is specified, returns the policy with the respective
+@code{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:
+
+
+@itemize *
+
+@item
+the escrow policy
+
+@item
+the separately encrypted master public key
+@end itemize
+
+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 @strong{truth}.
+
+The client MAY provide an @code{If-None-Match} header with an Etag.
+In that case, the server MUST additionally respond with an @code{304} status
+code in case the resource matches the provided Etag.
+
+@strong{Response}:
+
+
+@table @asis
+
+@item 200 OK@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1}:
+
+The escrow provider responds with an @ref{19,,EncryptedRecoveryDocument} object.
+
+@item 304 Not modified@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5}:
+
+The client requested the same resource it already knows.
+
+@item 400 Bad request@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1}:
+
+The @code{$ACCOUNT_PUB} is not an EdDSA public key.
+
+@item 402 Payment Required@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.3}:
+
+The account's balance is too low for the specified operation.
+See the Taler payment protocol specification for how to pay.
+
+@item 403 Forbidden@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4}:
+
+The required account signature was invalid.
+
+@item 404 Not found@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5}:
+
+The requested resource was not found.
+@end table
+
+@emph{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 @ref{19,,EncryptedRecoveryDocument}.
+
+@emph{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 @code{200 OK}.
+
+@emph{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.
+
+@emph{Anastasis-Account-Signature}: The client must provide Base-32 encoded EdDSA signature over hash of body with @code{$ACCOUNT_PRIV}, affirming desire to download the requested encrypted recovery document. The purpose used MUST be @code{TALER_SIGNATURE_ANASTASIS_POLICY_DOWNLOAD} (1401).
+@end deffn
+
+@anchor{anastasis post--policy-$ACCOUNT_PUB}@anchor{1a}
+@deffn {HTTP Post} 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.
+
+@strong{Request}:
+
+@*Query Parameters:
+
+@itemize *
+
+@item
+@code{pay} -- Optional argument, any non-empty value will do,
+suggested is @code{y} for @code{yes}.
+The client insists on making a payment for the respective
+account, even if this is not yet required. The server
+will respond with a @code{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 @code{304 Not modified}
+case.
+
+@item
+@code{timeout_ms=NUMBER} -- @emph{Optional.} If specified, the Anastasis server will
+wait up to @code{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.
+@end itemize
+
+
+@emph{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 @code{Expect: 100-Continue} header and wait for @code{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 @code{304} status code if the Etag matches
+the latest version already known to the server.
+
+@emph{Anastasis-Policy-Signature}: The client must provide Base-32 encoded EdDSA signature over hash of body with @code{$ACCOUNT_PRIV}, affirming desire to upload an encrypted recovery document.
+
+@emph{Payment-Identifier}: Base-32 encoded 32-byte payment identifier that was included in a previous payment (see @code{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 @strong{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 @code{402} response. When making payments, the server must include a fresh, randomly-generated payment-identifier in the payment request.
+
+@strong{Response}:
+
+
+@table @asis
+
+@item 204 No content@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5}:
+
+The encrypted recovery document was accepted and stored. @code{Anastasis-Version} and @code{Anastasis-UUID} headers
+indicate what version and UUID was assigned to this encrypted recovery document upload by the server.
+
+@item 304 Not modified@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5}:
+
+The same encrypted recovery document was previously accepted and stored. @code{Anastasis-Version} header
+indicates what version was previously assigned to this encrypted recovery document.
+
+@item 400 Bad request@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1}:
+
+The @code{$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.
+
+@item 402 Payment required@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.3}:
+
+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.
+
+@item 403 Forbidden@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4}:
+
+The required account signature was invalid. The response body may elaborate on the error.
+
+@item 413 Request entity too large@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.14}:
+
+The upload is too large @emph{or} too small. The response body may elaborate on the error.
+@end table
+
+@strong{Details:}
+@anchor{anastasis encryptedrecoverydocument}@anchor{19}
+@example
+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
+
+@}
+@end example
+@anchor{anastasis recoverydocument}@anchor{1b}
+@example
+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[];
+
+@}
+@end example
+@anchor{anastasis escrowmethod}@anchor{1c}
+@example
+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 `@w{`}/truth/`@w{`}.
+ 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
+
+@}
+@end example
+@anchor{anastasis decryptionpolicy}@anchor{1d}
+@example
+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[];
+
+@}
+@end example
+@end deffn
+
+@node Managing truth,,Manage policy,Anastasis REST API
+@anchor{anastasis managing-truth}@anchor{1e}@anchor{anastasis truth}@anchor{1f}
+@section Managing truth
+
+
+This API is used by the Anastasis client to deposit @strong{truth} or request a (encrypted) @strong{key share} with
+the escrow provider.
+
+An @strong{escrow method} specifies an Anastasis provider and how the user should
+authorize themself. The @strong{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.
+
+@anchor{anastasis post--truth-$UUID}@anchor{20}
+@deffn {HTTP Post} POST /truth/$UUID
+
+Upload a @ref{21,,TruthUploadRequest}-Object according to the policy the client created before (see @ref{1b,,RecoveryDocument}).
+If request has been seen before, the server should do nothing, and otherwise store the new object.
+
+@strong{Request:}
+
+@*Query Parameters:
+
+@itemize *
+
+@item
+@code{timeout_ms=NUMBER} -- @emph{Optional.} If specified, the Anastasis server will
+wait up to @code{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.
+@end itemize
+
+
+@strong{Response:}
+
+
+@table @asis
+
+@item 204 No content@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5}:
+
+Truth stored successfully.
+
+@item 304 Not modified@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5}:
+
+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.
+
+@item 402 Payment required@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.3}:
+
+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.
+
+@item 409 Conflict@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10}:
+
+The server already has some truth stored under this UUID. The client should check that it
+is generating UUIDs with enough entropy.
+
+@item 412 Precondition failed@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.13}:
+
+The selected authentication method is not supported on this provider.
+@end table
+
+@strong{Details:}
+@anchor{anastasis truthuploadrequest}@anchor{21}
+@example
+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 `@w{`}encrypted_truth`@w{`}.
+ 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;
+
+@}
+@end example
+@end deffn
+
+@anchor{anastasis get--truth-$UUID[?response=$H_RESPONSE]}@anchor{22}
+@deffn {HTTP Get} GET /truth/$UUID[?response=$H_RESPONSE]
+
+Get the stored encrypted key share. If @code{$H_RESPONSE} is specified by the client, the server checks
+if @code{$H_RESPONSE} matches the expected response specified before within the @ref{21,,TruthUploadRequest} (see @code{encrypted_truth}).
+Also, the user has to provide the correct @emph{truth_encryption_key} with every get request (see below).
+When @code{$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.
+
+@strong{Response}:
+
+
+@table @asis
+
+@item 200 OK@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1}:
+
+@ref{23,,EncryptedKeyShare} is returned in body (in binary).
+
+@item 202 Accepted@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.3}:
+
+The escrow provider will respond out-of-band (i.e. SMS).
+The body may contain human-readable instructions on next steps.
+
+@item >>208 Already Reported<<:
+
+An authentication challenge was recently send, client should
+simply respond to the pending challenge.
+
+@item 303 See other@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4}:
+
+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 @code{Location} header and allow the user to re-try the operation
+after successful authorization.
+
+@item 402 Payment required@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.3}:
+
+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.
+
+@item 403 Forbidden@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4}:
+
+The server requires a valid "response" to the challenge associated with the UUID.
+
+@item 404 Not found@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5}:
+
+The server does not know any truth under the given UUID.
+
+@item 410 Gone@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.11}:
+
+The server has not (recently) issued a challenge under the given UUID,
+but a reply was provided. (This does not apply for secure question.)
+
+@item 417 Expectation Failed@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.18}:
+
+The decrypted @code{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.
+
+@item 503 Service Unavailable@footnote{http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.4}:
+
+Server is out of Service.
+@end table
+
+@emph{Truth-Decryption-Key}: Key used to encrypt the @strong{truth} (see encrypted_truth within @ref{21,,TruthUploadRequest}) and which has to provided by the user. The key is stored with
+the according @ref{1c,,EscrowMethod}. The server needs this key to get the info out of @ref{21,,TruthUploadRequest} needed to verify the @code{$RESPONSE}.
+
+@strong{Details:}
+@anchor{anastasis encryptedkeyshare}@anchor{23}
+@example
+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
+
+@}
+@end example
+@anchor{anastasis keyshare}@anchor{24}
+@example
+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 `@w{`}key_share`@w{`}.
+ account_sig: EddsaSignature;
+
+@}
+@end example
+@end deffn
+
+@node Anastasis Reducer API,Authentication Methods,Anastasis REST API,Top
+@anchor{anastasis anastasis-reducer-api}@anchor{25}
+@chapter 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 @ref{26,,state} in JSON syntax and returns the new state in JSON syntax.
+
+For example a @strong{state} may take the following structure:
+
+@example
+@{
+ "backup_state": "CONTINENT_SELECTING",
+ "continents": [
+ "Europe",
+ "North_America"
+ ]
+@}
+@end example
+
+The new state depends on the previous one and on the transition @ref{27,,action} with its
+arguments given to the reducer. A @strong{transition argument} also is a statement in JSON syntax:
+
+@example
+@{
+ "continent": "Europe"
+@}
+@end example
+
+The new state returned by the reducer with the state and transition argument defined
+above would look like following for the transition @ref{27,,action} @code{select_continent}:
+
+@example
+@{
+ "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"
+ @}
+ ]
+@}
+@end example
+
+@menu
+* States::
+* Backup Reducer::
+* Recovery Reducer::
+* Reducer transitions::
+
+@end menu
+
+@node States,Backup Reducer,,Anastasis Reducer API
+@anchor{anastasis states}@anchor{28}
+@section States
+
+
+Overall, the reducer knows the following states:
+
+@quotation
+
+
+@itemize -
+
+@item
+
+@table @asis
+
+@item @strong{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.
+@end table
+
+@item
+
+@table @asis
+
+@item @strong{CONTINENT_SELECTING}: The user should specify the continent where they are living,
+
+so that we can show a list of countries to choose from.
+@end table
+
+@item
+
+@table @asis
+
+@item @strong{COUNTRY_SELECTING}: The user should specify the country where they are living,
+
+so that we can determine appropriate attributes, currencies and Anastasis
+providers.
+@end table
+
+@item
+
+@table @asis
+
+@item @strong{USER_ATTRIBUTES_COLLECTING}: The user should provide the country-specific personal
+
+attributes.
+@end table
+
+@item
+
+@table @asis
+
+@item @strong{AUTHENTICATIONS_EDITING}: The user should add authentication methods to be used
+
+during recovery.
+@end table
+
+@item
+@strong{POLICIES_REVIEWING}: The user should review the recovery policies.
+
+@item
+@strong{SECRET_EDITING}: The user should edit the secret to be backed up.
+
+@item
+
+@table @asis
+
+@item @strong{TRUTHS_PAYING}: The user needs to pay for one or more uploads of data associated
+
+with an authentication method.
+@end table
+
+@item
+@strong{POLICIES_PAYING}: The user needs to pay for storing the recovery policy document.
+
+@item
+@strong{BACKUP_FINISHED}: A backup has been successfully generated.
+
+@item
+
+@table @asis
+
+@item @strong{CHALLENGE_SELECTING}: The user needs to select an authorization challenge to
+
+proceed with recovery.
+@end table
+
+@item
+@strong{CHALLENGE_PAYING}: The user needs to pay to proceed with the authorization challenge.
+
+@item
+@strong{CHALLENGE_SOLVING}: The user needs to solve the authorization challenge.
+
+@item
+@strong{RECOVERY_FINISHED}: The secret of the user has been recovered.
+@end itemize
+@end quotation
+
+State names:
+
+@quotation
+
+
+@itemize -
+
+@item
+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).
+
+@item
+In COLLECTING-states, the user has to give certain values.
+
+@item
+In EDITING-states, the user is free to choose which values he wants to give.
+
+@item
+In REVEIWING-states, the user may make a few choices, but primarily is expected to affirm something.
+
+@item
+in PAYING-states, the user must make a payment.
+
+@item
+in FINISHED-states, the operation has definitively concluded.
+@end itemize
+@end quotation
+
+@node Backup Reducer,Recovery Reducer,States,Anastasis Reducer API
+@anchor{anastasis backup-reducer}@anchor{29}
+@section Backup Reducer
+
+@anchor{anastasis state}@anchor{26}@anchor{anastasis action}@anchor{27}
+
+@float Figure
+
+@image{anastasis-figures/anastasis_reducer_backup,,,fig-anastasis_reducer_backup,png}
+
+@caption{Backup states and their transitions.}
+
+@end float
+
+
+The illustration above shows the different states the reducer can have during a backup
+process.
+
+@node Recovery Reducer,Reducer transitions,Backup Reducer,Anastasis Reducer API
+@anchor{anastasis recovery-reducer}@anchor{2a}
+@section Recovery Reducer
+
+
+
+@float Figure
+
+@image{anastasis-figures/anastasis_reducer_recovery,,,fig-anastasis_reducer_recovery,png}
+
+@caption{Recovery states and their transitions.}
+
+@end float
+
+
+The illustration above shows the different states the reducer can have during a recovery
+process.
+
+@node Reducer transitions,,Recovery Reducer,Anastasis Reducer API
+@anchor{anastasis reducer-transitions}@anchor{2b}
+@section 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.
+
+@menu
+* Initial state::
+* Common transitions::
+* Backup transitions::
+* Recovery transitions::
+
+@end menu
+
+@node Initial state,Common transitions,,Reducer transitions
+@anchor{anastasis initial-state}@anchor{2c}
+@subsection Initial state
+
+
+The initial states for backup and recovery processes are:
+
+@strong{Initial backup state:}
+
+@example
+@{
+ "backup_state": "CONTINENT_SELECTING",
+ "continents": [
+ "Europe",
+ "North America"
+ ]
+@}
+@end example
+
+@strong{Initial recovery state:}
+
+@example
+@{
+ "recovery_state": "CONTINENT_SELECTING",
+ "continents": [
+ "Europe",
+ "North America"
+ ]
+@}
+@end example
+
+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 @code{continents_i18n} may be present.
+This field would be a map of language names to arrays of translated
+continent names:
+
+@example
+@{
+ "recovery_state": "CONTINENT_SELECTING",
+ "continents": [
+ "Europe",
+ "North America"
+ ]
+ "continents_i18n":
+ @{
+ "de_DE" : [
+ "Europa",
+ "Nordamerika"
+ ],
+ "de_CH" : [
+ "Europa",
+ "Nordamerika"
+ ]
+ @}
+@}
+@end example
+
+Translations must be given in the same order as the main English array.
+
+@node Common transitions,Backup transitions,Initial state,Reducer transitions
+@anchor{anastasis common-transitions}@anchor{2d}
+@subsection Common transitions
+
+
+@strong{select_continent:}
+
+Here the user specifies the continent they live on. Arguments (example):
+
+@example
+@{
+ "continent": "Europe"
+@}
+@end example
+
+The continent must be given using the English name from the @code{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:
+
+@example
+@{
+ "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"
+ @}
+ ]
+@}
+@end example
+
+Here @code{countries} is an array of countries on the @code{selected_continent}. For
+each country, the @code{code} is the ISO 3166-1 alpha-2 country code. The
+@code{continent} is only present because some countries span continents, the
+information is redundant and will always match @code{selected_continent}. The
+@code{name} is the name of the country in English, internationalizations of the
+name may be provided in @code{name_i18n}. The @code{currency} is @strong{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.
+
+@strong{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):
+
+@example
+@{
+ "country_code": "de",
+ "currency": "EUR"
+@}
+@end example
+
+The @code{country_code} must be an ISO 3166-1 alpha-2 country code from
+the array of @code{countries} of the reducer's state. The @code{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:
+
+@example
+@{
+ "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"
+ @}
+ @}
+@}
+@end example
+
+The array of @code{required_attributes} contains attributes about the user
+that must be provided includes:
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{type}: The type of the attribute, for now only @code{string} and @code{date} are
+supported.
+
+@item
+@strong{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.
+
+@item
+@strong{label}: A human-readable description of the attribute in English.
+Translated descriptions may be provided under @strong{label_i18n}.
+
+@item
+@strong{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 @strong{name},
+only the @strong{uuid} will be identical if the semantics is identicial.
+
+@item
+@strong{widget}: An optional name of a widget that is known to nicely render
+the attribute entry in user interfaces where named widgets are
+supported.
+
+@item
+@strong{validation-regex}: An optional extended POSIX regular expression
+that is to be used to validate (string) inputs to ensure they are
+well-formed.
+
+@item
+@strong{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).
+
+@item
+@strong{optional}: Optional boolean field that, if @code{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.
+@end itemize
+@end quotation
+
+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:
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{http_status}: HTTP status code, always @code{200} on success.
+
+@item
+@strong{methods}: Array of authentication methods supported by this
+provider. Includes the @strong{type} of the authentication method
+and the @strong{usage_fee} (how much the user must pay for authorization
+using this method during recovery).
+
+@item
+@strong{annual_fee}: Fee the provider charges to store the recovery
+policy for one year.
+
+@item
+@strong{truth_upload_fee}: Fee the provider charges to store a key share.
+
+@item
+@strong{truth_lifetime}: Taler-style relative time that specifies how
+long the provider will store truth data (key shares) after an upload.
+
+@item
+@strong{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.
+
+@item
+@strong{currency}: Currency in which the provider wants to be paid,
+will match all of the fees.
+
+@item
+@strong{storage_limit_in_megabytes}: Maximum size of an upload (for
+both recovery document and truth data) in megabytes.
+
+@item
+@strong{provider_name}: Human-readable name of the provider's business.
+
+@item
+@strong{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.
+@end itemize
+@end quotation
+
+If contacting the provider failed, the information returned is:
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{http_status}: HTTP status code (if available, possibly 0 if
+we did not even obtain an HTTP response).
+
+@item
+@strong{error_code}: Taler error code, never 0.
+@end itemize
+@end quotation
+
+@strong{add_provider}:
+
+This operation can be performed in state @code{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:
+
+@example
+@{
+ "urls": [
+ "http://localhost:8888/",
+ "http://localhost:8089/"
+ ]
+@}
+@end example
+
+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:
+
+@example
+@{
+ "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"
+ @}
+ @}
+@}
+@end example
+
+@node Backup transitions,Recovery transitions,Common transitions,Reducer transitions
+@anchor{anastasis backup-transitions}@anchor{2e}
+@subsection Backup transitions
+
+
+@strong{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 @code{null} or an empty string). Example
+arguments would be:
+
+@example
+@{
+ "identity_attributes": @{
+ "full_name": "Max Musterman",
+ "social_security_number": "123456789",
+ "birthdate": "2000-01-01",
+ "birthplace": "Earth"
+ @}
+@}
+@end example
+
+Note that at this stage, the state machines between backup and
+recovery diverge and the @code{recovery_state} will begin to look
+very different from the @code{backup_state}.
+
+For backups, if all required attributes are present, the reducer will
+transition to an @code{AUTHENTICATIONS_EDITING} state with the attributes added
+to it:
+
+@example
+@{
+ "backup_state": "AUTHENTICATIONS_EDITING",
+ "identity_attributes": @{
+ "full_name": "Max Musterman",
+ "social_security_number": "123456789",
+ "birthdate": "2000-01-01",
+ "birthplace": "Earth"
+ @}
+@}
+@end example
+
+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:
+
+@example
+@{
+ "backup_state": "ERROR",
+ "code": 8404,
+ "hint": "An input did not match the regular expression.",
+ "detail": "social_security_number"
+@}
+@end example
+
+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.
+
+@strong{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 @code{type} and @code{instructions} to
+be given to the user. The @code{challenge} is encrypted and stored at the
+Anastasis provider. The specific semantics of the value depend on the
+@code{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 @code{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 @code{mime_type} field must be provided to give the MIME type
+of the value encoded in @code{challenge}.
+
+@example
+@{
+ "authentication_method":
+ @{
+ "type": "question",
+ "mime_type" : "text/plain",
+ "instructions" : "What is your favorite GNU package?",
+ "challenge" : "E1QPPS8A",
+ @}
+@}
+@end example
+
+If the information provided is valid, the reducer will add the new
+authentication method to the array of authentication methods:
+
+@example
+@{
+ "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"
+ @}
+ ]
+@}
+@end example
+
+@strong{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:
+
+@example
+@{
+ "auth_method_index": 1
+@}
+@end example
+
+Assuming we begin with the state from the example above, this would
+remove the @code{email} authentication method, resulting in the following
+response:
+
+@example
+@{
+ "backup_state": "AUTHENTICATIONS_EDITING",
+ "authentication_methods": [
+ @{
+ "type": "question",
+ "mime_type" : "text/plain",
+ "instructions" : "What is your favorite GNU package?",
+ "challenge" : "gdb",
+ @}
+ ]
+@}
+@end example
+
+If the index is invalid, the reducer will instead
+transition into an @code{ERROR} state.
+
+@strong{next} (from @code{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:
+
+@example
+@{
+ "providers": [
+ "http://localhost:8088/",
+ "http://localhost:8089/"
+ ]
+@}
+@end example
+
+The resulting state provides the suggested recovery policies in a way suitable
+for presentation to the user:
+
+@example
+@{
+ "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/"
+ @}
+ ]
+ @}
+ ]
+@}
+@end example
+
+For each recovery policy, the state includes the specific details of which
+authentication @code{methods} must be solved to recovery the secret using this
+policy. The @code{methods} array specifies the index of the
+@code{authentication_method} in the @code{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
+@code{ERROR} state instead of suggesting policies.
+
+@strong{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:
+
+@example
+@{
+ "policy": [
+ @{
+ "auth_method_index": 1,
+ "provider": "http://localhost:8088/"
+ @},
+ @{
+ "auth_method_index": 3,
+ "provider": "http://localhost:8089/"
+ @}
+ ]
+@}
+@end example
+
+Note that the specified providers must already be in the
+@code{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:
+
+@example
+@{
+ "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/"
+ @}
+ ]
+ @}
+ ]
+@}
+@end example
+
+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 @code{ERROR} state instead of
+adding the new policy.
+
+@strong{delete_policy:}
+
+This transition allows the deletion of a recovery policy. The argument
+simply specifies the index of the policy to delete, for example:
+
+@example
+@{
+ "policy_index": 3
+@}
+@end example
+
+Given as input the state from the example above, the expected new state would
+be:
+
+@example
+@{
+ "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/"
+ @}
+ ]
+ @}
+ ]
+@}
+@end example
+
+If the index given is invalid, the reducer will transition into an @code{ERROR} state
+instead of deleting a policy.
+
+@strong{next} (from @code{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 @code{SECRET_EDITING} state:
+
+@example
+@{
+ "backup_state": "SECRET_EDITING",
+@}
+@end example
+
+If the array of @code{policies} is currently empty, the reducer will transition
+into an @code{ERROR} state instead of allowing the user to continue.
+
+@strong{enter_secret:}
+
+This transition provides the reducer with the actual core @code{secret} of the user
+that Anastasis is supposed to backup (and possibly recover). The argument is
+simply the Crockford-Base32 encoded @code{value} together with its @code{mime} type,
+for example:
+
+@example
+@{
+ "secret": @{
+ "value": "EDJP6WK5EG50",
+ "mime" : "text/plain"
+ @}
+@}
+@end example
+
+If the application is unaware of the format, it set the @code{mime} field to @code{null}.
+
+After adding a secret, the reducer may transition into different states
+depending on whether payment(s) are necessary. If payments are needed, the
+@code{secret} will be stored in the state under @code{core_secret}. Applications
+should be careful when persisting the resulting state, as the @code{core_secret}
+is not protected in the @code{PAYING} states. The @code{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
+@code{BACKUP_FINISHED} state and (if applicable) delete the @code{core_secret} as an
+additional safety measure.
+
+Example results are thus:
+
+@example
+@{
+ "backup_state": "TRUTHS_PAYING",
+ "core_secret" : "DATA",
+ "payments": [
+ "taler://pay/...",
+ "taler://pay/..."
+ ]
+@}
+@end example
+
+@example
+@{
+ "backup_state": "POLICIES_PAYING",
+ "core_secret" : "DATA",
+ "payments": [
+ "taler://pay/...",
+ "taler://pay/..."
+ ]
+@}
+@end example
+
+@example
+@{
+ "backup_state": "BACKUP_FINISHED",
+@}
+@end example
+
+@strong{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 @code{timeout} value that specifies how long the
+reducer may wait (in long polling) for the payment to complete:
+
+@example
+@{
+ "timeout": @{ "d_ms" : 5000 @},
+@}
+@end example
+
+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
+@code{BACKUP_FINISHED} state (if all payments have been completed and the backup
+finished), or into an @code{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:
+
+@example
+@{
+ "backup_state": "ERROR",
+ "http_status" : 500,
+ "upload_status" : 52,
+ "provider_url" : "https://bad.example.com/",
+@}
+@end example
+
+Here, the fields have the following meaning:
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{http_status} is the HTTP status returned by the Anastasis provider.
+
+@item
+@strong{upload_status} is the Taler error code return by the provider.
+
+@item
+@strong{provider_url} is the base URL of the failing provider.
+@end itemize
+@end quotation
+
+In the above example, 52 would thus imply that the Anastasis provider failed to
+store information into its database.
+
+@node Recovery transitions,,Backup transitions,Reducer transitions
+@anchor{anastasis recovery-transitions}@anchor{2f}
+@subsection Recovery transitions
+
+
+@strong{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 @code{null} or an empty string). The
+arguments are identical to the @strong{enter_user_attributes} transition from
+the backup process. Example arguments would thus be:
+
+@example
+@{
+ "identity_attributes": @{
+ "full_name": "Max Musterman",
+ "social_security_number": "123456789",
+ "birthdate": "2000-01-01",
+ "birthplace": "Earth"
+ @}
+@}
+@end example
+
+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:
+
+@example
+@{
+ "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": @{
+ ...
+ @}
+@}
+@end example
+
+The @code{recovery_document} is an internal representation of the recovery
+information and of no concern to the user interface. The pertinent information
+is in the @code{recovery_information}. Here, the @code{challenges} array is a list
+of possible challenges the user could attempt to solve next, while @code{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 @code{provider_url} from where the recovery document was
+obtained and its @code{version} are also provided. Each challenge comes with
+four mandatory fields:
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{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.
+
+@item
+@strong{cost}: This is the amount the Anastasis provider will charge
+to allow the user to pass the challenge.
+
+@item
+@strong{type}: This is the type of the challenge, as a string.
+
+@item
+@strong{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 @code{type}.
+@end itemize
+@end quotation
+
+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 @code{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:
+
+@example
+@{
+ "recovery_state": "ERROR",
+ "error_message": "account unknown to Anastasis server",
+ "error_code": 9,
+@}
+@end example
+
+Here, the @code{error_code} is from the @code{enum ANASTASIS_RecoveryStatus}
+and describes precisely what failed about the download, while the
+@code{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 @code{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.
+
+@strong{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 @code{change_version} transition,
+which takes a provider URL and policy version as arguments:
+
+@example
+@{
+ "provider_url": "https://localhost:8080/",
+ "version": 2
+@}
+@end example
+
+Note that using a version of 0 implies fetching "the latest version". The
+resulting states are the same as those of the @code{enter_user_attributes}
+transition, except that the recovery document version is not necessarily the
+latest available version at the provider.
+
+@strong{select_challenge:}
+
+Selecting a challenge takes different, depending on the state of the payment.
+A comprehensive example for @code{select_challenge} would be:
+
+@example
+@{
+ "uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30"
+ "timeout" : @{ "d_ms" : 5000 @},
+ "payment_secret": "3P4561HAMHRRYEYD6CM6J7TS5VTD5SR2K2EXJDZEFSX92XKHR4KG"
+@}
+@end example
+
+The @code{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 @code{payment_secret} identifies the previous payment request, and
+@code{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 @code{CHALLENGE_SOLVING} or @code{CHALLENGE_PAYING}
+states. In @code{CHALLENGE_SOLVING}, the new state will primarily specify
+the selected challenge:
+
+@example
+@{
+ "backup_state": "CHALLENGE_SOLVING",
+ "selected_challenge_uuid": "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30"
+@}
+@end example
+
+In @code{CHALLENGE_PAYING}, the new state will include instructions for payment
+in the @code{challenge_feedback}. In general, @code{challenge_feedback} includes
+information about attempted challenges, with the final state being @code{solved}:
+
+@example
+@{
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": @{
+ // ...
+ @}
+ "challenge_feedback": @{
+ "80H646H5ZBR453C02Y5RT55VQSJZGM5REWFXVY0SWXY1TNE8CT30" : @{
+ "state" : "solved"
+ @}
+ @}
+@}
+@end example
+
+Challenges feedback for a challenge can have many different @code{state} values
+that applications must all handle. States other than @code{solved} are:
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{payment}: Here, the user must pay for a challenge. An example would be:
+
+@example
+@{
+ "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"
+ @}
+ @}
+@}
+@end example
+@end itemize
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{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.
+
+@example
+@{
+ "recovery_state": "CHALLENGE_SOLVING",
+ "recovery_information": @{
+ // ...
+ @}
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": @{
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": @{
+ "state": "body",
+ "body": "CROCKFORDBASE32ENCODEDBODY",
+ "http_status": 403,
+ "mime_type" : "anything/possible"
+ @}
+ @}
+@}
+@end example
+
+@item
+@strong{hint}: Here, the server provided human-readable hint for
+how to solve the challenge. Note that the @code{hint} provided this
+time is from the Anastasis provider and may differ from the @code{instructions}
+for the challenge under @code{recovery_information}:
+
+@example
+@{
+ "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
+ @}
+ @}
+@}
+@end example
+
+@item
+@strong{details}: Here, the server provided a detailed JSON status response
+related to solving the challenge:
+
+@example
+@{
+ "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
+ @}
+ @}
+@}
+@end example
+@end itemize
+
+@quotation
+
+
+@itemize -
+
+@item
+@strong{redirect}: To solve the challenge, the user must visit the indicated
+Web site at @code{redirect_url}, for example to perform video authentication:
+@end itemize
+
+@quotation
+
+@example
+@{
+ "recovery_state": "CHALLENGE_SOLVING",
+ "recovery_information": @{
+ // ...
+ @}
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": @{
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": @{
+ "state": "redirect",
+ "redirect_url": "https://videoconf.example.com/",
+ "http_status": 303
+ @}
+ @}
+@}
+@end example
+
+
+@itemize -
+
+@item
+@strong{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.
+@end itemize
+
+@example
+@{
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": @{
+ // ...
+ @}
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": @{
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": @{
+ "state": "server-failure",
+ "http_status": "500",
+ "error_code": 52
+ @}
+ @}
+@}
+@end example
+
+
+@itemize -
+
+@item
+@strong{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.
+@end itemize
+
+@example
+@{
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": @{
+ // ...
+ @}
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": @{
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": @{
+ "state": "truth-unknown",
+ "error_code": 8108
+ @}
+ @}
+@}
+@end example
+
+
+@itemize -
+
+@item
+@strong{rate-limit-exceeded}:
+@end itemize
+
+@example
+@{
+ "recovery_state": "CHALLENGE_SELECTING",
+ "recovery_information": @{
+ // ...
+ @}
+ "selected_challenge_uuid": "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0",
+ "challenge_feedback": @{
+ "TXYKGE1SJZHJ4M2FKSV1P2RZVNTHZFB9E3A79QE956D3SCAWXPK0": @{
+ "state": "rate-limit-exceeded",
+ "error_code": 8121
+ @}
+ @}
+@}
+@end example
+@end quotation
+@end quotation
+@end quotation
+@end quotation
+
+@strong{pay:}
+
+With a @code{pay} transition, the application indicates to the reducer that
+a payment may have been made. Here, it is again possible to specify an
+optional @code{timeout} argument for long-polling, for example:
+
+@example
+@{
+ "payment_secret": "ABCDADF242525AABASD52525235ABABFDABABANALASDAAKASDAS"
+ "timeout" : @{ "d_ms" : 5000 @},
+@}
+@end example
+
+Depending on the type of the challenge and the result of the operation, the
+new state may be @code{CHALLENGE_SOLVING} (if say the SMS was now sent to the
+user), @code{CHALLENGE_SELECTING} (if the answer to the security question was
+correct), @code{RECOVERY_FINISHED} (if this was the last challenge that needed to
+be solved) or still @code{CHALLENGE_PAYING} (if the challenge was not actually
+paid for). For sample messages, see the different types of
+@code{challenge_feedback} in the section about @code{select_challenge}.
+
+@strong{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:
+
+@example
+@{
+ "answer": "answer to security question"
+@}
+@end example
+
+@example
+@{
+ "pin": 1234
+@}
+@end example
+
+@example
+@{
+ "hash": "SOMEBASE32ENCODEDHASHVALUE"
+@}
+@end example
+
+@node Authentication Methods,,Anastasis Reducer API,Top
+@anchor{anastasis anastasis-auth-methods}@anchor{30}@anchor{anastasis authentication-methods}@anchor{31}
+@chapter 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.
+
+@menu
+* SMS (sms): SMS sms.
+* Email verification (email): Email verification email.
+* Video identification (vid): Video identification vid.
+* Security question (qa): Security question qa.
+* Snail mail verification (post): Snail mail verification post.
+
+@end menu
+
+@node SMS sms,Email verification email,,Authentication Methods
+@anchor{anastasis sms-sms}@anchor{32}
+@section SMS (sms)
+
+
+Sends an SMS with a code (prefixed with @code{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 @code{$RESPONSE} under @ref{1e,,Managing truth}).
+If the transmitted code is correct, the server responses with the requested
+encrypted key share.
+
+@node Email verification email,Video identification vid,SMS sms,Authentication Methods
+@anchor{anastasis email-verification-email}@anchor{33}
+@section Email verification (email)
+
+
+Sends an email with a code (prefixed with @code{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 @code{$RESPONSE} under @ref{1e,,Managing truth}). If the transmitted code is correct, the server responses with the
+requested encrypted key share.
+
+@node Video identification vid,Security question qa,Email verification email,Authentication Methods
+@anchor{anastasis video-identification-vid}@anchor{34}
+@section Video identification (vid)
+
+
+Requires the user to identify via video-call. In the video-call, the
+user is told the code (prefixed with @code{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.
+
+@node Security question qa,Snail mail verification post,Video identification vid,Authentication Methods
+@anchor{anastasis security-question-qa}@anchor{35}
+@section Security question (qa)
+
+
+Asks the user a security question. The user sends back a @strong{salted}
+hash over the answer. The @strong{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 @strong{key-salt} for the
+decryption of the (encrypted) @strong{key share}. This ensures that the key share
+remains irrecoverable without the answer even if the Anastasis provider
+storing the security question is malicious.
+
+@node Snail mail verification post,,Security question qa,Authentication Methods
+@anchor{anastasis snail-mail-verification-post}@anchor{36}
+@section Snail mail verification (post)
+
+
+Sends physical mail (snail mail) with a code (prefixed with @code{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
+@code{$RESPONSE} under @ref{1e,,Managing truth}). If the transmitted code is correct,
+the server responds with the requested encrypted key share.
+
+@c %**end of body
+@bye