frosix

Multiparty signature service (experimental)
Log | Files | Refs | README | LICENSE

rest.rst (19501B)


      1 ..
      2   This file is part of Frosix
      3   Copyright (C) 2022, 2023 Joel Urech
      4 
      5   Frosix is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Frosix is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Frosix; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 
     16   @author Christian Grothoff
     17   @author Joel Urech
     18 
     19 ========
     20 REST API
     21 ========
     22 
     23 .. _config:
     24 
     25 -----------------------
     26 Receiving Configuration
     27 -----------------------
     28 
     29 .. http:get:: /config
     30 
     31   Obtain the configuration details of the provider.
     32   
     33 **Response:**
     34 
     35 Returns a `ProviderConfigurationResponse`_.
     36 
     37 
     38 .. _ProviderConfigurationResponse:
     39 .. ts:def:: ProviderConfigurationResponse
     40 
     41   interface ProviderConfigurationResponse {
     42 
     43     // Protocol identifier, clarifies that this is a Frosix provider.
     44     name: "frosix";
     45 
     46     // libtool-style representation of the Exchange protocol version, see
     47     // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
     48     // The format is "current:revision:age".
     49     version: string;
     50 
     51     // What is the name of this provider?
     52     business_name: string;
     53 
     54     // Supported authorization methods.
     55     methods: AuthorizationMethodConfig[];
     56 
     57     // Payment required to create a key.
     58     // Not yet implemented!
     59     // key_creation_fee: Amount;
     60 
     61     // Salt value with 128 bits of entropy.
     62     // Different providers will use different high-entropy salt values.
     63     // The resulting **provider salt** is then used in various operations to ensure
     64     // cryptographic operations differ by provider. 
     65     // A provider must never change its salt value.
     66     provider_salt: string;
     67 
     68     // Public key of this provider.
     69     public_key: string;
     70 
     71   }
     72 
     73 .. _AuthorizationMethodConfig:
     74 .. ts:def:: AuthorizationMethodConfig
     75 
     76   interface AuthorizationMethodConfig {
     77     // Name of the authorization method.
     78     type: string;
     79 
     80     // Fee for issuing a signature share using this method.
     81     // Not yet implemented!
     82     // cost: Amount;
     83 
     84   }
     85 
     86 
     87 .. _terms:
     88 
     89 --------------------------
     90 Receiving Terms of Service
     91 --------------------------
     92 
     93 .. http:get:: /terms
     94 
     95   Obtain the terms of service of the provider.
     96   // Not yet implemented!
     97 
     98 
     99 .. _seed:
    100 
    101 ----
    102 Seed
    103 ----
    104 
    105 .. http:get:: /seed
    106 
    107   Returns an high-entropy seed. Binary data in the HTTP body.
    108   This API should be used every time the clients need high entropy.
    109   The entropy returned MUST be mixed with locally generated entropy.
    110 
    111 
    112 .. _key:
    113 
    114 --------------
    115 Key Generation
    116 --------------
    117 
    118 
    119 Distributed Key Generation
    120 ^^^^^^^^^^^^^^^^^^^^^^^^^^
    121 
    122 .. http:post:: /dkg-commitment/$ID/
    123 
    124   Let the provider compute a commitment for a polynomial with degree threshold-1.
    125   ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `ContextString`, `AuthHash`, `Identifier`, `NumOfParticipants`, `Threshold`, `PublicProviderSalt`, "FROSIX-DKG-ID".
    126 
    127   **Request:**
    128 
    129   Upload a `DkgCommitmentRequest`.
    130 
    131   **Response:**
    132 
    133   :http:statuscode:`201 Created`:
    134     The provider responds with a `DkgCommitmentResponse`.
    135 
    136   **Details:**
    137 
    138   .. _DkgCommitmentRequest:
    139   .. ts:def:: DkgCommitmentRequest
    140 
    141     interface DkgCommitmentRequest {
    142 
    143       // Unique identifier within the group.
    144       provider_index: Identifier;
    145 
    146       // Minimum number of participants needed to sign a message.
    147       threshold: Threshold;
    148 
    149       // ContextString is the main source of entropy to sample the commitments and should draw its entropy from several sources (e.g. with GET /seed from each participating provider).
    150       context_string: ContextString;
    151 
    152       // Salted hash of authentication data, i.e. phone number, e-mail address, ...
    153       // Or hash of the public key used to verify the secret answer of a security question.
    154       auth_hash: AuthHash;
    155 
    156       // Public keys of all participating providers.
    157       // Number of public key equals the total number of participants (n).
    158       providers_public_keys: ProviderPublicKey[];
    159 
    160     }
    161 
    162   .. _DkgCommitmentResponse:
    163   .. ts:def:: DkgCommitmentResponse
    164   
    165     interface DkgCommitmentResponse {
    166 
    167       // Unique identifier within the group
    168       provider_index: Identifier;
    169 
    170       // List of commitments, corresponding to the computed polynomial.
    171       dkg_commitment: DkgCommitment[threshold];
    172 
    173       // Zero Knowledge Proof of the corresponding secret of the computed polynomial.
    174       zkp: DkgZkp;
    175 
    176       // Public Key to derive an symmetric key to encrypt the secret share intended for this provider (ECDHE).
    177       provider_public_key: EphemeralPublicKey;
    178     }
    179 
    180   .. _DkgZkp:
    181   .. ts:def:: DkgZkp
    182 
    183     interface DkgZkp {
    184       r: R;
    185       z: z;
    186     }
    187 
    188 
    189 .. http:post:: /dkg-shares/$ID
    190 
    191   Upload the DKG commitments of all other participants and receive encrypted shares for all other participants.
    192   ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `ContextString`, `AuthHash`, `Identifier`, `NumOfParticipants`, `Threshold`, `PublicProviderSalt`, "FROSIX-DKG-ID".
    193 
    194   **Request:**
    195 
    196   Upload a `DkgSecretSharesRequest`_.
    197 
    198   **Response:**
    199 
    200   :http:statuscode:`201 Created`:
    201     The provider responds with a `DkgSecretSharesResponse`_.
    202 
    203   **Details:**
    204 
    205   .. _DkgSecretSharesRequest:
    206   .. ts:def:: DkgSecretSharesRequest:
    207 
    208     interface DkgSecretSharesRequest {
    209 
    210       // Identifier within the group.
    211       provider_index: Identifier;
    212 
    213       // Minimum number of participants needed to sign a message.
    214       threshold: Threshold;
    215 
    216       // Number of participants participating in the distributed key generation.
    217       num_of_participants: NumOfParticipants;
    218 
    219       // ContextString is the source of entropy to recover commitments.
    220       context_string: ContextString;
    221 
    222       // Salted hash of some challenge data, i.e. phone number, e-mail address, ...
    223       // Or hash of the public key used to verify the secret answer of a security question.
    224       auth_hash: AuthHash;
    225 
    226       // Public keys of all participating providers.
    227       // Number of public key equals total number of participants (n).
    228       providers_public_keys: ProviderPublicKey[];
    229 
    230       // The commitments of all participants
    231       dkg_commitments: DkgCommitmentResponse[num_of_participants - 1];
    232 
    233     }
    234 
    235   .. _DkgSecretSharesResponse:
    236   .. ts:def:: DkgSecretSharesResponse:
    237 
    238     interface DkgSecretSharesResponse {
    239 
    240       // The secret shares
    241       secret_shares: DkgSecretShare[num_of_participants - 1];
    242 
    243     }
    244 
    245   .. _DkgSecretShare:
    246   .. ts:def:: DkgSecretShare:
    247 
    248     interface DkgSecretShare {
    249 
    250       // Identifier of the target participant
    251       target: Identifier;
    252 
    253       // identifier of the issuer
    254       issuer: Identifier;
    255 
    256       // Ephemeral key
    257       ephemeral_key: EphemeralKey;
    258 
    259       enc_secret_share_data: [[
    260 
    261         // The secret share - symmetric encrypted
    262         secret_share: SecretShare; ]]
    263 
    264     }
    265 
    266 
    267 .. http:post:: /dkg-key/$ID
    268 
    269   Upload all encrypted secret shares intended for this participant.
    270   ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `ContextString`, `AuthHash`, `Identifier`, `NumOfParticipants`, `Threshold`, `PublicProviderSalt`, "FROSIX-DKG-ID".
    271 
    272   **Request:**
    273 
    274   Upload a `KeyGenerateRequest`_.
    275 
    276   **Response:**
    277 
    278   :http:statuscode:`204 No Content`:
    279     Key pair was successfully created and stored.
    280   :http:statuscode:`404 Not Found`:
    281 	  The provider does not know the provided ``$ID``.
    282   :http:statuscode:`409 Conflict`:
    283     The service already has a key pair stored under the resulting ``$ID`` (hash of resulting public key).
    284   :http:statuscode:`402 Payment required`:
    285 	  If the desired storage duration is longer than the default value in the terms of service of the provider, the provider must be paid additionally.
    286 
    287   **Details:**
    288 
    289   .. _KeyGenerateRequest:
    290   .. ts:def:: KeyGenerateRequest:
    291 
    292     interface KeyGenerateRequest {
    293 
    294       // Identifier within the group.
    295       provider_index: Identifier;
    296 
    297       // Minimum number of participants needed to sign a message. (needed to calculate secret polynomail)
    298       threshold: Threshold;
    299 
    300       // ContextString is the source of entropy to recover the secret value behind the providers commitment.
    301       context_string: ContextString;
    302 
    303       // Salted hash of some challenge data, i.e. phone number, e-mail address, ...
    304       // Or hash of the public key used to verify the secret answer of a security question.
    305       auth_hash: AuthHash;
    306 
    307       // Public keys of all participating providers.
    308       // Number of public key equals total number of participants (n).
    309       providers_public_keys: ProviderPublicKey[];
    310 
    311       // For how many years from now would the client like us to store the truth?
    312       expiration: Years;
    313 
    314       // All secret shares targeting this participant
    315       secret_shares: DkgSecretShare[num_of_participants - 1];
    316 
    317     }
    318 
    319   .. _KeyGenerateResponse:
    320   .. ts:def:: KeyGenerateResponse:
    321 
    322     interface KeyGenerateResponse {
    323 
    324       // Public Key of created Distributed Secret Key
    325       public_key: PublicKey
    326 
    327       // The signature is over the public key and the received authentication hash.
    328       // This signature allows to verify the correctness of the authentication hash and to proof to a third person that this provider is involved in this signing group.
    329       provider_signature: ProviderSignature
    330 
    331     }
    332 
    333 
    334 .. _challenge:
    335 
    336 -----------------
    337 Challenge Request
    338 -----------------
    339 
    340 .. http:post:: /auth-request/$ID
    341 
    342   Let the provider create and send a challenge-code.
    343   ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `EncryptionKey`, `MessageHash`, "FROSIX-AUTH".
    344 
    345   **Request:**
    346 
    347   The request must be a `ChallengeCodeRequest`_.
    348 
    349   **Response:**
    350 
    351   :http:statuscode:`200 OK`:
    352     The provider responds with an empty body.
    353   :http:statuscode:`402 Payment Required`:
    354     The provider requires payment to issue a challenge code.
    355 
    356   **Details:**
    357 
    358   .. _ChallengeCodeRequest:
    359   .. ts:def:: ChallengeCodeRequest:
    360 
    361     interface ChallengeCodeRequest {
    362 
    363       // Encryption key
    364       encryption_key: EncryptionKey;
    365 
    366       // Authentication method
    367       auth_method: AuthMethod;
    368 
    369       // Authentication data
    370       auth_data: AuthData;
    371 
    372       // Authentication nonce
    373       auth_nonce: AuthNonce;
    374 
    375       // Hash of the message.
    376       // The message is bound to the challenge code. A challenge code can therefore only be used for a specific message.
    377       message_hash: MessageHash;
    378     }
    379 
    380 
    381 .. _sign:
    382 
    383 -------
    384 Signing
    385 -------
    386 
    387 .. http:post:: /sig-commitment/$ID
    388   
    389   A provider first authenticates an incoming request and then issues a commitment, which is bound to the submitted message.
    390   ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `EncryptionKeyHash`, `MessageHash`, "FROSIX-SIG".
    391 
    392   **Request:**
    393 
    394   The request must be a `SignatureCommitmentRequest`_.
    395    
    396   **Response:**
    397 
    398   :http:statuscode:`200 OK`:
    399 	  The provider responds with a `SignatureCommitmentResponse`_.
    400   :http:statuscode:`403 Forbidden`:
    401 	  The client failed the authentication challenge.
    402   :http:statuscode:`404 Not Found`:
    403 	  The provider does not know the provided ``$ID``.
    404   :http:statuscode:`404 Not found`:
    405 	  The provider does not know the given ``$ID``.
    406   :http:statuscode:`410 Gone`:
    407 	  The challenge has expired.
    408   :http:statuscode:`429 Too Many Requests`:
    409 	  Too many attempts.
    410 
    411   **Details:**
    412 
    413   .. _SignatureCommitmentRequest:
    414   .. ts:def:: SignatureCommitmentRequest:
    415 
    416     interface SigantureCommitmentRequest {
    417 
    418       // Hash of the encryption key, used to identify the corresponding entry in the database.
    419       encryption_key_hash: EncryptionKeyHash;
    420 
    421       // Authentication method in order to authorize the incoming request.
    422       auth_method: AuthMethod;
    423 
    424       // (Optional) If its a challenge code based authentication, authentication data contains the hash of the challenge code.
    425       auth_data: AuthData;
    426 
    427       // (Optional) If its a security question, this authentication signature over the `MessageHash` is created with a private key which is derived from the secret answer.
    428       auth_sig: AuthSig;
    429 
    430       // (Optional) Public key to verify the `AuthSig` signature. Gets hashed and compared to the hash stored in the provider's database.
    431       auth_pub: AuthPub;
    432 
    433       // Hash of the message, serves as input for the key derivation function to sample a commitment.
    434       message_hash: MessageHash;
    435 
    436     }
    437 
    438   .. _SignatureCommitmentResponse:
    439   .. ts:def:: SignatureCommitmentResponse:
    440 
    441     interface SignatureCommitmentResponse {
    442 
    443       // First part of the commitment.
    444       // Commitments are used to ensure, that every provider behaves well.
    445       hiding_commitment: SigCommitment;
    446 
    447       // Second part of the commitment.
    448       binding_commitment: SigCommitment;
    449 
    450     }
    451 
    452 
    453 .. http:post:: /sig-share/$ID
    454 
    455   Ask the provider to compute a signature share.
    456   ``$ID`` is the SHA-512 hash over the following data in Crockford base32 endoding: `EncryptionKeyHash`, `MessageHash`, "FROSIX-SIG".
    457 
    458   **Request:**
    459 
    460   Upload a `SignatureShareRequest`.
    461 
    462   **Response:**
    463 
    464   :http:statuscode:`200 OK`:
    465 	  The provider responds with a `SignatureShareResponse`.
    466   :http:statuscode:`404 Not found`:
    467 	  The provider does not know the given ``$ID``.
    468 
    469   **Details:**
    470 
    471   .. _SignatureShareRequest:
    472   .. ts:def:: SignatureShareRequest
    473    
    474     interface SignatureShareRequest {
    475 
    476       // Symmetric key to decrypt the key material
    477       encryption_key: EncryptionKey;
    478 
    479       // Hash of the message
    480       message_hash: MessageHash;   
    481 
    482       // Sorted list of commitments of all participating providers.
    483       // The own commitment has to be included.
    484       commitments: SignatureCommitmentResponse[];
    485 
    486     }
    487 
    488   .. _SignatureCommmitment:
    489   .. ts:def:: SignatureCommitment
    490 
    491     interface SignatureCommitment {
    492 
    493       // Identifier
    494       identifier: Identifier;
    495 
    496       // First part of the commitment.
    497       // Commitments are used to ensure, that every provider behaves well.
    498       hiding_commitment: SigCommitment;
    499 
    500       // Second part of the commitment.
    501       binding_commitment: SigCommitment;
    502 
    503     }
    504 
    505   .. _SignatureShareResponse:
    506   .. ts:def:: SignatureShareResponse
    507 
    508     interface SignatureShareResponse {
    509       
    510       // The resulting signature share
    511       signature_share: SigShare;
    512       
    513       // The partial public key for convenience only - could be ommited
    514       public_key_share: PublicKeyShare;
    515 
    516     }
    517 
    518 
    519 .. _delete-key:
    520 
    521 ----------
    522 Delete Key
    523 ----------
    524 
    525 .. http:delete:: /dkg-key/$ID
    526   
    527   Deletes the key data if an entry is found with the ``$ID``.
    528   ``$ID`` is the `EncryptionKeyHash`.
    529    
    530   **Response:**
    531 
    532   :http:statuscode:`200 OK`:
    533 	  The provider responds with a `SignatureCommitmentResponse`_.
    534 
    535 
    536 .. _encodings-ref:
    537 
    538 ----------------
    539 Common encodings
    540 ----------------
    541 
    542 This section describes how certain types of values are represented throughout the API.
    543 
    544 .. _base32:
    545 
    546 Binary Data
    547 ^^^^^^^^^^^
    548 
    549 .. ts:def:: foobase
    550 
    551   type Base32 = string;
    552 
    553 Binary data is generally encoded using Crockford's variant of Base32
    554 (http://www.crockford.com/wrmg/base32.html), except that "U" is not excluded
    555 but also decodes to "V" to make OCR easy.  We will still simply use the JSON
    556 type "base32" and the term "Crockford Base32" in the text to refer to the
    557 resulting encoding.
    558 
    559 
    560 Hash codes
    561 ^^^^^^^^^^
    562 Hash codes are strings representing base32 encoding of the respective
    563 hashed data. See `base32`_.
    564 
    565 .. ts:def:: HashCode
    566 
    567   // 64-byte hash code.
    568   type HashCode = string;
    569 
    570 .. ts:def:: SHA512HashCode
    571 
    572    type SHA512HashCode = HashCode;
    573 
    574 .. ts:def:: PublicProviderSalt
    575 
    576    type PublicProviderSalt: HashCode;
    577 
    578 .. ts:def:: ContextString
    579 
    580    // To generate a "good" ContextString,
    581    // the client has to get fresh entropy from at least
    582    // all participating providers (GET seed) and from itself.
    583    type ContextString = SHA512HashCode;
    584 
    585 .. ts:def:: MessageHash
    586 
    587    // Hash of the message, which shall be signed. 
    588    type MessageHash = SHA512HashCode;
    589 
    590 .. ts:def:: EncryptionKey
    591 
    592    // The encryption key is used to encrypt and decrypt the key data stored in the provider's database.
    593    type EncryptionKey = SHA512HashCode;
    594 
    595 .. ts:def:: EncryptionKeyHash
    596 
    597   // Hash of the encryption key. Used to identify the corresponding entry in the provider's database.
    598   type EncryptionKeyHash = SHA512HashCode;
    599 
    600 .. ts:def:: AuthHash
    601 
    602   // The authentication hash is a salted hash of the authentication data which gets stored in the provider's database.
    603   type AuthHash = SHA512HashCode;
    604 
    605 .. ts:def:: AuthNonce
    606 
    607   // Nonce used as salt to hash `AuthData` to receive `AuthHash`.
    608   tpye AuthNonce = SHA512HashCode;
    609 
    610 
    611 Curve25519
    612 ^^^^^^^^^^
    613 32-byte values representig base32 encoding of either a point on Curve25519 or a scalar for operations on points on Curve 25519.
    614 
    615 .. ts:def:: Cs25519Point
    616 
    617    type Cs25519Point = string;
    618 
    619 .. ts:def:: Cs25519Scalar
    620 
    621    type Cs25519Scalar = string;
    622 
    623 .. ts:def:: SigCommitment
    624 
    625    type SigCommitment = Cs25519Point;
    626 
    627 .. ts:def:: DkgCommitment
    628 
    629    type DkgCommitment = Cs25519Point;
    630 
    631 .. ts:def:: SecretShare
    632 
    633    type SecretShare = Cs25519Scalar;
    634 
    635 .. ts:def:: EddsaPublicKey
    636 
    637    // EdDSA and ECDHE public keys always point on Curve25519
    638    // and represented  using the standard 256 bits Ed25519 compact format,
    639    // converted to Crockford `Base32`.
    640    type EddsaPublicKey = string;
    641 
    642 .. ts:def:: EddsaPrivateKey
    643 
    644    // EdDSA and ECDHE public keys always point on Curve25519
    645    // and represented  using the standard 256 bits Ed25519 compact format,
    646    // converted to Crockford `Base32`.
    647    type EddsaPrivateKey = string;
    648 
    649 
    650 Signatures
    651 ^^^^^^^^^^
    652 
    653 .. ts:def:: EddsaSignature
    654 
    655   // EdDSA signatures are transmitted as 64-bytes `base32`
    656   // binary-encoded objects with just the R and S values (base32_ binary-only).
    657   type EddsaSignature = string;
    658 
    659 .. ts:def:: R
    660 
    661    // The signature challenge.
    662    type R = Cs25519Point;
    663 
    664 .. ts:def:: z
    665 
    666    // A single share of the resulting signature.
    667    type z = Cs25519Scalar;
    668 
    669 .. ts:def:: ProviderSignature
    670 
    671   // Signature of a provider over the public key and the authentication data.
    672   type ProviderSignature = EddsaSignature;
    673 
    674 .. ts:def:: AuthSig
    675 
    676   // Signature over the message with a private key derived from the secret answer.
    677   type AuthSig = EddsaSignature;
    678 
    679 
    680 Keys
    681 ^^^^
    682 
    683 .. ts:def:: SecretKeyShare
    684 
    685    type SecretKeyShare = Cs25519Scalar;
    686 
    687 .. ts:def:: PublicKeyShare
    688 
    689    type PublicKeyShare = Cs25519Point;
    690 
    691 .. ts:def:: PublicKey
    692 
    693    type PublicKey = Cs25519Point;
    694 
    695 .. ts:def:: SigShare
    696 
    697    type SigShare = Cs25519Scalar;
    698 
    699 .. ts:def:: ProviderPublicKey
    700 
    701    type ProviderPublicKey = EddsaPublicKey;
    702 
    703 .. ts:def:: EphemeralPublicKey
    704 
    705    type EphemeralPublicKey = EddsaPublicKey;
    706 
    707 .. ts:def:: EphemeralKey
    708    
    709    type EphemeralKey = EddsaPublicKey;
    710 
    711 .. ts:def:: AuthPub
    712   
    713    type AuthPub = EddsaPublicKey;
    714 
    715 Integers
    716 ^^^^^^^^
    717 
    718 .. ts:def:: UInt8
    719 
    720    // JavaScript numbers restricted to the range of 0-255
    721    type UInt8 = number;
    722 
    723 .. ts:def:: Identifier
    724 
    725    // Identifier in the group
    726    type Identifier = UInt8;
    727 
    728 .. ts:def:: Threshold
    729 
    730    type Threshold = UInt8;
    731 
    732 .. ts:def:: NumOfParticipants
    733    
    734    type NumOfParticipants = UInt8;
    735 
    736 .. ts:def:: Years
    737 
    738    type Years = number;
    739 
    740 
    741 Strings
    742 ^^^^^^^
    743 
    744 .. ts:def:: AuthMethod
    745 
    746    type AuthMethod = string;
    747 
    748 .. ts:def:: AuthData
    749 
    750    type AuthData = string;