diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2022-02-16 22:01:05 +0100 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2022-02-16 22:01:05 +0100 |
commit | 8bdf6ab19df70c16d335ecf82f2c3b2117eeb70e (patch) | |
tree | fe38fc98807feb6892052ee091b2b5f0a70ab17a /src/include | |
parent | b73be40ccd9ad0ef4a985f252099c867f698896d (diff) | |
download | exchange-8bdf6ab19df70c16d335ecf82f2c3b2117eeb70e.tar.gz exchange-8bdf6ab19df70c16d335ecf82f2c3b2117eeb70e.tar.bz2 exchange-8bdf6ab19df70c16d335ecf82f2c3b2117eeb70e.zip |
[age restriction] progress 14/n - withdraw and deposit
Age restriction support for
- withdraw is done and tested
- deposit is done and tested
TODOs:
- melt/refresh/reveal
- link
------
Added functions
- TALER_age_restriction_commit
- TALER_age_commitment_derive
- TALER_age_commitment_hash
- TALER_age_restriction_commitment_free_inside
- Hash of age commitment passed around API boundaries
Exchangedb adjustments for denominations
- all prepared statements re: denominations now handle age_mask
- signature parameters adjusted
Hash and signature verification of /keys adjusted
- Hashes of (normal) denominations and age-restricted denominations are
calculated seperately
- The hash of the age-restricted ones will then be added to the other
hash
- The total hash is signed/verified
Tests for withdraw with age restriction added
- TALER_EXCHANGE_DenomPublickey now carries age_mask
- TALER_TESTING_cmd_withdraw_amount* takes age parameter
- TALER_TESTING_find_pk takes boolean age_restricted
- WithdrawState carries age_commitment and its hash
- withdraw_run derives new age commitment, if applicable
- Added age parameter to testing (13 as example)
Various Fixes and changes
- Fixes of post handler for /management/extensions
- Fixes for offline tool extensions signing
- Slight refactoring of extensions
- Age restriction extension simplified
- config is now global to extension
- added global TEH_age_restriction_enabled and TEH_age_mask in
taler-exchange-httpd
- helper functions and macros introduced
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/taler_crypto_lib.h | 213 | ||||
-rw-r--r-- | src/include/taler_exchange_service.h | 10 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 28 | ||||
-rw-r--r-- | src/include/taler_extensions.h | 78 | ||||
-rw-r--r-- | src/include/taler_json_lib.h | 11 | ||||
-rw-r--r-- | src/include/taler_signatures.h | 18 | ||||
-rw-r--r-- | src/include/taler_testing_lib.h | 37 |
7 files changed, 318 insertions, 77 deletions
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index ab5202baa..9bbf29de4 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -306,37 +306,6 @@ struct TALER_MasterSignatureP struct GNUNET_CRYPTO_EddsaSignature eddsa_signature; }; -/* - * @brief Type of a list of age groups, represented as bit mask. - * - * The bits set in the mask mark the edges at the beginning of a next age - * group. F.e. for the age groups - * 0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-* - * the following bits are set: - * - * 31 24 16 8 0 - * | | | | | - * oooooooo oo1oo1o1 o1o1o1o1 ooooooo1 - * - * A value of 0 means that the exchange does not support the extension for - * age-restriction. - */ -struct TALER_AgeMask -{ - uint32_t mask; -}; - -/** - * @brief Age restriction commitment of a coin. - */ -struct TALER_AgeHash -{ - /** - * The commitment is a SHA-256 hash code. - */ - struct GNUNET_ShortHashCode shash; -}; - /** * @brief Type of public keys for Taler coins. The same key material is used @@ -364,6 +333,29 @@ struct TALER_CoinSpendPrivateKeyP struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv; }; +/** + * @brief Type of private keys for age commitment in coins. + */ +struct TALER_AgeCommitmentPrivateKeyP +{ + /** + * Taler uses EdDSA for coins when signing age verification attestation. + */ + struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv; +}; + + +/** + * @brief Type of public keys for age commitment in coins. + */ +struct TALER_AgeCommitmentPublicKeyP +{ + /** + * Taler uses EdDSA for coins when signing age verification attestation. + */ + struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub; +}; + /** * @brief Type of signatures made with Taler coins. @@ -765,6 +757,46 @@ struct TALER_BlindedDenominationSignature }; +/* *************** Age Restriction *********************************** */ + +/* + * @brief Type of a list of age groups, represented as bit mask. + * + * The bits set in the mask mark the edges at the beginning of a next age + * group. F.e. for the age groups + * 0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-* + * the following bits are set: + * + * 31 24 16 8 0 + * | | | | | + * oooooooo oo1oo1o1 o1o1o1o1 ooooooo1 + * + * A value of 0 means that the exchange does not support the extension for + * age-restriction. + */ +struct TALER_AgeMask +{ + uint32_t mask; +}; + +/** + * @brief Age commitment of a coin. + */ +struct TALER_AgeCommitmentHash +{ + /** + * The commitment is a SHA-256 hash code. + */ + struct GNUNET_ShortHashCode shash; +}; + +extern const struct TALER_AgeCommitmentHash TALER_ZeroAgeCommitmentHash; +#define TALER_AgeCommitmentHash_isNullOrZero(ph) ((NULL == ph) || \ + (0 == memcmp (ph, \ + & \ + TALER_ZeroAgeCommitmentHash, \ + sizeof(struct \ + TALER_AgeCommitmentHash)))) /** * @brief Type of public signing keys for verifying blindly signed coins. @@ -944,9 +976,10 @@ struct TALER_CoinPublicInfo struct TALER_DenominationHash denom_pub_hash; /** - * Hash of the age commitment. + * Hash of the age commitment. If no age commitment was provided, it must be + * set to all zeroes. */ - struct TALER_AgeHash age_commitment_hash; + struct TALER_AgeCommitmentHash age_commitment_hash; /** * (Unblinded) signature over @e coin_pub with @e denom_pub, @@ -1117,7 +1150,7 @@ TALER_denom_sig_free (struct TALER_DenominationSignature *denom_sig); enum GNUNET_GenericReturnValue TALER_denom_blind (const struct TALER_DenominationPublicKey *dk, const union TALER_DenominationBlindingKeyP *coin_bks, - const struct TALER_AgeHash *age_commitment_hash, + const struct TALER_AgeCommitmentHash *age_commitment_hash, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_ExchangeWithdrawValues *alg_values, struct TALER_CoinPubHash *c_hash, @@ -1349,7 +1382,7 @@ TALER_withdraw_request_hash ( */ void TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_AgeHash *age_commitment_hash, + const struct TALER_AgeCommitmentHash *age_commitment_hash, struct TALER_CoinPubHash *coin_h); @@ -1402,8 +1435,9 @@ struct TALER_FreshCoin struct TALER_CoinSpendPrivateKeyP coin_priv; /** - * FIXME-Oec: Age-verification vector, as pointer: Dyn alloc! + * Optional hash of an age commitment bound to this coin, maybe NULL. */ + const struct TALER_AgeCommitmentHash *h_age_commitment; }; @@ -1571,6 +1605,7 @@ TALER_planchet_blinding_secret_create ( * @param alg_values algorithm specific values * @param bks blinding secrets * @param coin_priv coin private key + * @param ach hash of age commitment to bind to this coin, maybe NULL * @param[out] c_hash set to the hash of the public key of the coin (needed later) * @param[out] pd set to the planchet detail for TALER_MERCHANT_tip_pickup() and * other withdraw operations, `pd->blinded_planchet.cipher` will be set @@ -1582,6 +1617,7 @@ TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk, const struct TALER_ExchangeWithdrawValues *alg_values, const union TALER_DenominationBlindingKeyP *bks, const struct TALER_CoinSpendPrivateKeyP *coin_priv, + const struct TALER_AgeCommitmentHash *ach, struct TALER_CoinPubHash *c_hash, struct TALER_PlanchetDetail *pd); @@ -1613,6 +1649,7 @@ TALER_planchet_detail_free (struct TALER_PlanchetDetail *pd); * @param blind_sig blind signature from the exchange * @param bks blinding key secret * @param coin_priv private key of the coin + * @param ach hash of age commitment that is bound to this coin, maybe NULL * @param c_hash hash of the coin's public key for verification of the signature * @param alg_values values obtained from the exchange for the withdrawal * @param[out] coin set to the details of the fresh coin @@ -1624,6 +1661,7 @@ TALER_planchet_to_coin ( const struct TALER_BlindedDenominationSignature *blind_sig, const union TALER_DenominationBlindingKeyP *bks, const struct TALER_CoinSpendPrivateKeyP *coin_priv, + const struct TALER_AgeCommitmentHash *ach, const struct TALER_CoinPubHash *c_hash, const struct TALER_ExchangeWithdrawValues *alg_values, struct TALER_FreshCoin *coin); @@ -2202,6 +2240,7 @@ TALER_wallet_account_setup_sign ( * @param deposit_fee the deposit fee we expect to pay * @param h_wire hash of the merchant’s account details * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange) + * @param h_age_commitment hash over the age commitment, if applicable to the denomination (maybe NULL) * @param h_extensions hash over the extensions * @param h_denom_pub hash of the coin denomination's public key * @param coin_priv coin’s private key @@ -2216,6 +2255,7 @@ TALER_wallet_deposit_sign ( const struct TALER_Amount *deposit_fee, const struct TALER_MerchantWireHash *h_wire, const struct TALER_PrivateContractHash *h_contract_terms, + const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_ExtensionContractHash *h_extensions, const struct TALER_DenominationHash *h_denom_pub, struct GNUNET_TIME_Timestamp wallet_timestamp, @@ -2232,6 +2272,7 @@ TALER_wallet_deposit_sign ( * @param deposit_fee the deposit fee we expect to pay * @param h_wire hash of the merchant’s account details * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange) + * @param h_age_commitment hash over the age commitment (maybe all zeroes, if not applicable to the denomination) * @param h_extensions hash over the extensions * @param h_denom_pub hash of the coin denomination's public key * @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future @@ -2247,6 +2288,7 @@ TALER_wallet_deposit_verify ( const struct TALER_Amount *deposit_fee, const struct TALER_MerchantWireHash *h_wire, const struct TALER_PrivateContractHash *h_contract_terms, + const struct TALER_AgeCommitmentHash *h_commitment_hash, const struct TALER_ExtensionContractHash *h_extensions, const struct TALER_DenominationHash *h_denom_pub, struct GNUNET_TIME_Timestamp wallet_timestamp, @@ -2283,6 +2325,7 @@ TALER_wallet_melt_sign ( * @param melt_fee the melt fee we expect to pay * @param rc refresh session we are committed to * @param h_denom_pub hash of the coin denomination's public key + * @param h_age_commitment hash of the age commitment (may be NULL) * @param coin_pub coin’s public key * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_MELT * @return #GNUNET_OK if the signature is valid @@ -2293,6 +2336,7 @@ TALER_wallet_melt_verify ( const struct TALER_Amount *melt_fee, const struct TALER_RefreshCommitmentP *rc, const struct TALER_DenominationHash *h_denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendSignatureP *coin_sig); @@ -2321,6 +2365,7 @@ TALER_wallet_link_sign (const struct TALER_DenominationHash *h_denom_pub, * @param transfer_pub transfer public key * @param h_coin_ev hash of the coin envelope * @param old_coin_pub old coin key that the link signature is for + * @param h_age_commitment hash of age commitment. Maybe NULL, if not applicable. * @param coin_sig resulting signature * @return #GNUNET_OK if the signature is valid */ @@ -2330,6 +2375,7 @@ TALER_wallet_link_verify ( const struct TALER_TransferPublicKeyP *transfer_pub, const struct TALER_BlindedCoinHash *h_coin_ev, const struct TALER_CoinSpendPublicKeyP *old_coin_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_CoinSpendSignatureP *coin_sig); @@ -3149,5 +3195,100 @@ TALER_exchange_offline_extension_config_hash_verify ( const struct TALER_MasterSignatureP *master_sig ); +/* + * @brief Representation of an age commitment: one public key per age group. + * + * The number of keys must be be the same as the number of bits set in the + * corresponding age mask. + */ +struct TALER_AgeCommitment +{ + + /* The age mask defines the age groups that were a parameter during the + * generation of this age commitment */ + struct TALER_AgeMask mask; + + /* The number of public keys, which must be the same as the number of + * groups in the mask. + */ + size_t num_pub; + + /* The list of #num_pub public keys. In must have same size as the number of + * age groups defined in the mask. + * + * A hash of this list is the hashed commitment that goes into FDC + * calculation during the withdraw and refresh operations for new coins. That + * way, the particular age commitment becomes mandatory and bound to a coin. + * + * The list has been allocated via GNUNET_malloc. + */ + struct TALER_AgeCommitmentPublicKeyP *pub; + + /* The number of private keys, which must be at most num_pub_keys. One minus + * this number corresponds to the largest age group that is supported with + * this age commitment. + */ + size_t num_priv; + + /* List of #num_priv private keys. + * + * Note that the list can be _smaller_ than the corresponding list of public + * keys. In that case, the wallet can sign off only for a subset of the age + * groups. + * + * The list has been allocated via GNUNET_malloc. + */ + struct TALER_AgeCommitmentPrivateKeyP *priv; +}; + +/* + * @brief Generates a hash of the public keys in the age commitment. + * + * @param commitment the age commitment - one public key per age group + * @param[out] hash resulting hash + */ +void +TALER_age_commitment_hash ( + const struct TALER_AgeCommitment *commitment, + struct TALER_AgeCommitmentHash *hash); + +/* + * @brief Generates an age commitent for the given age. + * + * @param mask The age mask the defines the age groups + * @param age The actual age for which an age commitment is generated + * @param seed The seed that goes into the key generation. MUST be choosen uniformly random. + * @param commitment[out] The generated age commitment, ->priv and ->pub allocated via GNUNET_malloc on success + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +enum GNUNET_GenericReturnValue +TALER_age_restriction_commit ( + const struct TALER_AgeMask *mask, + const uint8_t age, + const uint32_t seed, + struct TALER_AgeCommitment *commitment); + +/* + * @brief Derives another, equivalent age commitment for a given one. + * + * @param orig Original age commitment + * @param seed Used to move the points on the elliptic curve in order to generate another, equivalent commitment. + * @param derived[out] The resulting age commitment, ->priv and ->pub allocated via GNUNET_malloc on success. + * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + */ +enum GNUNET_GenericReturnValue +TALER_age_commitment_derive ( + const struct TALER_AgeCommitment *orig, + const uint32_t seed, + struct TALER_AgeCommitment *derived); + +/* + * @brief helper function to free memory inside a struct TALER_AgeCommitment + * @param cmt the commitment from which internal memory should be freed. Note + * that cmt itself is NOT freed! + */ +void +TALER_age_restriction_commitment_free_inside ( + struct TALER_AgeCommitment *cmt); #endif diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 8c1b4bde2..fef09f721 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -159,11 +159,6 @@ struct TALER_EXCHANGE_DenomPublicKey * revoked by the exchange. */ bool revoked; - - /** - * Is the denomination age-restricted? - */ - bool age_restricted; }; @@ -785,6 +780,7 @@ TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh); * @param h_extensions hash over the extensions * @param h_denom_pub hash of the coin denomination's public key * @param coin_priv coin’s private key + * @param age_commitment age commitment that went into the making of the coin, might be NULL * @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline @@ -799,6 +795,7 @@ TALER_EXCHANGE_deposit_permission_sign ( const struct TALER_ExtensionContractHash *h_extensions, const struct TALER_DenominationHash *h_denom_pub, const struct TALER_CoinSpendPrivateKeyP *coin_priv, + const struct TALER_AgeCommitment *age_commitment, struct GNUNET_TIME_Timestamp wallet_timestamp, const struct TALER_MerchantPublicKeyP *merchant_pub, struct GNUNET_TIME_Timestamp refund_deadline, @@ -924,6 +921,7 @@ TALER_EXCHANGE_deposit ( const char *merchant_payto_uri, const struct TALER_WireSaltP *wire_salt, const struct TALER_PrivateContractHash *h_contract_terms, + const struct TALER_AgeCommitmentHash *h_age_commitment, const json_t *extension_details, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_DenominationSignature *denom_sig, @@ -1496,6 +1494,7 @@ typedef void * @param reserve_priv private key of the reserve to withdraw from * @param ps secrets of the planchet * caller must have committed this value to disk before the call (with @a pk) + * @param ach hash of the age commitment that should be bound to this coin. Maybe NULL. * @param res_cb the callback to call when the final result for this request is available * @param res_cb_cls closure for @a res_cb * @return NULL @@ -1508,6 +1507,7 @@ TALER_EXCHANGE_withdraw ( const struct TALER_EXCHANGE_DenomPublicKey *pk, const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_PlanchetMasterSecretP *ps, + const struct TALER_AgeCommitmentHash *ach, TALER_EXCHANGE_WithdrawCallback res_cb, void *res_cb_cls); diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index ec647e9c6..f0a6f8bd6 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -70,6 +70,12 @@ struct TALER_EXCHANGEDB_DenominationKeyInformationP * Signed properties of the denomination key. */ struct TALER_DenominationKeyValidityPS properties; + + /** + * If denomination was setup for age restriction, non-zero age mask. + * Note that the mask is not part of the signature. + */ + struct TALER_AgeMask age_mask; }; @@ -295,7 +301,7 @@ struct TALER_EXCHANGEDB_TableData struct { struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_AgeHash age_hash; + struct TALER_AgeCommitmentHash age_hash; uint64_t denominations_serial; struct TALER_DenominationSignature denom_sig; } known_coins; @@ -644,7 +650,7 @@ struct TALER_EXCHANGEDB_DenominationKeyMetaData * A value of 0 means that the denomination does not support the extension for * age-restriction. */ - struct TALER_AgeMask age_restrictions; + struct TALER_AgeMask age_mask; }; @@ -1262,6 +1268,13 @@ struct TALER_EXCHANGEDB_Refresh struct TALER_CoinSpendSignatureP coin_sig; /** + * Hash of the age commitment used to sign the coin, if age restriction was + * applicable to the denomination. May be all zeroes if no age restriction + * applies. + */ + struct TALER_AgeCommitmentHash h_age_commitment; + + /** * Refresh commitment this coin is melted into. */ struct TALER_RefreshCommitmentP rc; @@ -1307,6 +1320,13 @@ struct TALER_EXCHANGEDB_MeltListEntry struct TALER_DenominationHash h_denom_pub; /** + * Hash of the age commitment used to sign the coin, if age restriction was + * applicable to the denomination. May be all zeroes if no age restriction + * applies. + */ + struct TALER_AgeCommitmentHash h_age_commitment; + + /** * How much value is being melted? This amount includes the fees, * so the final amount contributed to the melt is this value minus * the fee for melting the coin. We include the fee in what is @@ -1606,6 +1626,7 @@ typedef enum GNUNET_GenericReturnValue * @param cls closure * @param rowid unique serial ID for the refresh session in our DB * @param denom_pub denomination public key of @a coin_pub + * @param h_age_commitment age commitment that went into the signing of the coin, may be NULL * @param coin_pub public key of the coin * @param coin_sig signature from the coin * @param amount_with_fee amount that was deposited including fee @@ -1618,6 +1639,7 @@ typedef enum GNUNET_GenericReturnValue void *cls, uint64_t rowid, const struct TALER_DenominationPublicKey *denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *amount_with_fee, @@ -2758,7 +2780,7 @@ struct TALER_EXCHANGEDB_Plugin const struct TALER_CoinPublicInfo *coin, uint64_t *known_coin_id, struct TALER_DenominationHash *denom_pub_hash, - struct TALER_AgeHash *age_hash); + struct TALER_AgeCommitmentHash *age_hash); /** diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h index f00f3ed56..b7b93e178 100644 --- a/src/include/taler_extensions.h +++ b/src/include/taler_extensions.h @@ -86,6 +86,31 @@ TALER_extensions_load_taler_config ( const struct GNUNET_CONFIGURATION_Handle *cfg); /* + * Check the given obj to be a valid extension object and fill the fields + * accordingly. + */ +enum GNUNET_GenericReturnValue +TALER_extensions_is_json_config ( + json_t *obj, + int *critical, + const char **version, + json_t **config); + +/* + * Sets the configuration of the extensions from a given JSON object. + * + * he JSON object must be of type ExchangeKeysResponse as described in + * https://docs.taler.net/design-documents/006-extensions.html#exchange + * + * @param cfg JSON object containting the configuration for all extensions + * @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found + * or any particular configuration couldn't be parsed. + */ +enum GNUNET_GenericReturnValue +TALER_extensions_load_json_config ( + json_t *cfg); + +/* * Returns the head of the linked list of extensions */ const struct TALER_Extension * @@ -156,20 +181,6 @@ TALER_extensions_verify_json_config_signature ( struct TALER_MasterSignatureP *extensions_sig, struct TALER_MasterPublicKeyP *master_pub); -/* - * Sets the configuration of the extensions from a given JSON object. - * - * The JSON object must be of type ExchangeKeysResponse as described in - * https://docs.taler.net/design-documents/006-extensions.html#exchange - * - * @param cfg Handle to the TALER configuration - * @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found - * or any particular configuration couldn't be parsed. - */ -enum GNUNET_GenericReturnValue -TALER_extensions_load_json_config ( - json_t *extensions); - /* * TALER Age Restriction Extension @@ -221,6 +232,45 @@ char * TALER_age_mask_to_string ( const struct TALER_AgeMask *mask); +/** + * Returns true when age restriction is configured and enabled. + */ +bool +TALER_extensions_age_restriction_is_enabled (); + +/** + * Returns true when age restriction is configured (might not be _enabled_, + * though). + */ +bool +TALER_extensions_age_restriction_is_configured (); + +/** + * Returns the currently set age mask. Note that even if age restriction is + * not enabled, the age mask might be have a non-zero value. + */ +struct TALER_AgeMask +TALER_extensions_age_restriction_ageMask (); + + +/** + * Returns the amount of age groups defined. 0 means no age restriction + * enabled. + */ +size_t +TALER_extensions_age_restriction_num_groups (); + +/** + * Parses a JSON object { "age_groups": "a:b:...y:z" }. + * + * @param root is the json object + * @param[out] mask on succes, will contain the age mask + * @return #GNUNET_OK on success and #GNUNET_SYSERR on failure. + */ +enum GNUNET_GenericReturnValue +TALER_JSON_parse_age_groups (const json_t *root, + struct TALER_AgeMask *mask); + /* * TODO: Add Peer2Peer Extension diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index b7bcd845f..e3e47222b 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -608,17 +608,6 @@ TALER_JSON_extensions_config_hash (const json_t *config, struct TALER_ExtensionConfigHash *eh); /** - * Parses a JSON object `{ "extension": "age_restriction", "mask": uint32 }`. - * - * @param root is the json object - * @param[out] mask on succes, will contain the age mask - * @return #GNUNET_OK on success and #GNUNET_SYSERR on failure. - */ -enum GNUNET_GenericReturnValue -TALER_JSON_parse_agemask (const json_t *root, - struct TALER_AgeMask *mask); - -/** * Canonicalize a JSON input to a string according to RFC 8785. */ char * diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 17ed4b57a..e3d9a8939 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -419,6 +419,11 @@ struct TALER_LinkDataPS struct TALER_TransferPublicKeyP transfer_pub; /** + * Hash of the age commitment, if applicable. Can be all zero + */ + struct TALER_AgeCommitmentHash h_age_commitment; + + /** * Hash of the blinded new coin. */ struct TALER_BlindedCoinHash coin_envelope_hash; @@ -477,6 +482,12 @@ struct TALER_DepositRequestPS struct TALER_PrivateContractHash h_contract_terms GNUNET_PACKED; /** + * Hash over the age commitment that went into the coin. Maybe all zero, if + * age commitment isn't applicable to the denomination. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** * Hash over extension attributes shared with the exchange. */ struct TALER_ExtensionContractHash h_extensions GNUNET_PACKED; @@ -710,6 +721,13 @@ struct TALER_RefreshMeltCoinAffirmationPS struct TALER_DenominationHash h_denom_pub GNUNET_PACKED; /** + * If age commitment was provided during the withdrawal of the coin, this is + * the hash of the age commitment vector. It must be all zeroes if no age + * commitment was provided. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** * How much of the value of the coin should be melted? This amount * includes the fees, so the final amount contributed to the melt is * this value minus the fee for melting the coin. We include the diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 69cb9f68f..ab8b64fc5 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -66,11 +66,13 @@ TALER_TESTING_make_wire_details (const char *payto); * * @param keys array of keys to search * @param amount coin value to look for + * @param age_restricted must the denomination be age restricted? * @return NULL if no matching key was found */ const struct TALER_EXCHANGE_DenomPublicKey * TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_Amount *amount); + const struct TALER_Amount *amount, + bool age_restricted); /** @@ -1278,6 +1280,7 @@ TALER_TESTING_cmd_exec_transfer (const char *label, * @param label command label. * @param reserve_reference command providing us with a reserve to withdraw from * @param amount how much we withdraw. + * @param age if > 0, age restriction applies * @param expected_response_code which HTTP response code * we expect from the exchange. * @return the withdraw command to be executed by the interpreter. @@ -1286,6 +1289,7 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_withdraw_amount (const char *label, const char *reserve_reference, const char *amount, + uint8_t age, unsigned int expected_response_code); @@ -1298,6 +1302,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label, * @param label command label. * @param reserve_reference command providing us with a reserve to withdraw from * @param amount how much we withdraw. + * @param age if > 0, age restriction applies. * @param coin_ref reference to (withdraw/reveal) command of a coin * from which we should re-use the private key * @param expected_response_code which HTTP response code @@ -1309,6 +1314,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key ( const char *label, const char *reserve_reference, const char *amount, + uint8_t age, const char *coin_ref, unsigned int expected_response_code); @@ -2138,6 +2144,19 @@ TALER_TESTING_cmd_wire_del (const char *label, unsigned int expected_http_status, bool bad_sig); +/** + * Sign all extensions that the exchange has to offer, f. e. the extension for + * age restriction. This has to be run before any withdrawal of age restricted + * can be performed. + * + * @param label command label. + * @param config_filename configuration filename. + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_offline_sign_extensions (const char *label, + const char *config_filename); + /** * Sign all exchange denomination and online signing keys @@ -2422,10 +2441,10 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, */ #define TALER_TESTING_SIMPLE_TRAITS(op) \ op (bank_row, const uint64_t) \ - op (reserve_priv, const struct TALER_ReservePrivateKeyP) \ - op (planchet_secret, const struct TALER_PlanchetMasterSecretP) \ - op (refresh_secret, const struct TALER_RefreshMasterSecretP) \ - op (reserve_pub, const struct TALER_ReservePublicKeyP) \ + op (reserve_priv, const struct TALER_ReservePrivateKeyP) \ + op (planchet_secret, const struct TALER_PlanchetMasterSecretP) \ + op (refresh_secret, const struct TALER_RefreshMasterSecretP) \ + op (reserve_pub, const struct TALER_ReservePublicKeyP) \ op (merchant_priv, const struct TALER_MerchantPrivateKeyP) \ op (merchant_pub, const struct TALER_MerchantPublicKeyP) \ op (merchant_sig, const struct TALER_MerchantSignatureP) \ @@ -2438,8 +2457,8 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, op (exchange_bank_account_url, const char *) \ op (taler_uri, const char *) \ op (payto_uri, const char *) \ - op (kyc_url, const char *) \ - op (web_url, const char *) \ + op (kyc_url, const char *) \ + op (web_url, const char *) \ op (row, const uint64_t) \ op (payment_target_uuid, const uint64_t) \ op (array_length, const unsigned int) \ @@ -2464,7 +2483,9 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, #define TALER_TESTING_INDEXED_TRAITS(op) \ op (denom_pub, const struct TALER_EXCHANGE_DenomPublicKey) \ op (denom_sig, const struct TALER_DenominationSignature) \ - op (planchet_secrets, const struct TALER_PlanchetMasterSecretP) \ + op (age_commitment, struct TALER_AgeCommitment) \ + op (h_age_commitment, struct TALER_AgeCommitmentHash) \ + op (planchet_secrets, const struct TALER_PlanchetMasterSecretP) \ op (exchange_wd_value, const struct TALER_ExchangeWithdrawValues) \ op (coin_priv, const struct TALER_CoinSpendPrivateKeyP) \ op (coin_pub, const struct TALER_CoinSpendPublicKeyP) \ |