diff options
Diffstat (limited to 'texinfo/anastasis.texi')
-rw-r--r-- | texinfo/anastasis.texi | 2792 |
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 |