taler-merchant-httpd_token-keys.h (7440B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2026 Taler Systems SA 4 5 TALER 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 TALER 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 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file src/backend/taler-merchant-httpd_token-keys.h 18 * @brief shared token family key lookup, lifetime extension and creation 19 * for orders and fountains; also provides fountain key windows 20 * @author Christian Blättler 21 * @author Bohdan Potuzhnyi 22 */ 23 #ifndef TALER_MERCHANT_HTTPD_TOKEN_KEYS_H 24 #define TALER_MERCHANT_HTTPD_TOKEN_KEYS_H 25 26 #include "taler-merchant-httpd.h" 27 #include "taler/taler_merchant_util.h" 28 #include "merchantdb_lib.h" 29 #include "merchant-database/get_token_family_key.h" 30 31 /** 32 * Hard cap on the ``key_window_size`` of a fountain grant. Every 33 * advertised future slot may require minting (and storing) a fresh 34 * blind-signing key pair on ``GET /fountain/info``, so an unbounded 35 * window would be a denial-of-service vector. 36 */ 37 #define TMH_MAX_FOUNTAIN_KEY_WINDOW 12 38 39 /** 40 * Hard cap on the total number of token envelopes in one 41 * ``POST /fountain/withdraw`` request. Matches the cap on token 42 * outputs of the pay endpoint. 43 */ 44 #define TMH_MAX_FOUNTAIN_ENVELOPES 64 45 46 47 /** 48 * Extend the lifetime of existing private keys covering @a valid_at 49 * until at least @a sign_until. Does not create a key. Order creation 50 * also calls this when reusing a key already added to the contract. 51 * 52 * @param connection connection to report errors on 53 * @param instance_id instance owning the token family 54 * @param slug slug of the token family 55 * @param valid_at time at which the tokens must be valid 56 * @param sign_until how long the private key must remain usable 57 * @return #GNUNET_OK on success, #GNUNET_NO if an error response was 58 * queued, #GNUNET_SYSERR on hard failure 59 */ 60 enum GNUNET_GenericReturnValue 61 TMH_token_key_extend ( 62 struct MHD_Connection *connection, 63 const char *instance_id, 64 const char *slug, 65 struct GNUNET_TIME_Timestamp valid_at, 66 struct GNUNET_TIME_Timestamp sign_until); 67 68 69 /** 70 * Ensure that an issue key of token family @a slug covering @a valid_at 71 * exists and that its private key remains usable for signing until at 72 * least @a sign_until. If a key covering @a valid_at exists but its 73 * private key would be deleted earlier, the private key's lifetime is 74 * extended; only if no key covers @a valid_at at all is a new key pair 75 * generated and stored in the database. 76 * 77 * @param connection connection to report errors on 78 * @param instance_id instance owning the token family 79 * @param slug slug of the token family 80 * @param valid_at time at which tokens signed with the key must be valid; 81 * determines the key's validity period 82 * @param sign_until how long the private key must remain usable 83 * @param[out] key_details set to the key (public and private part), its 84 * validity bounds and the token family details; on success the 85 * caller must release it via #TMH_token_key_details_free() 86 * @param[out] minted set to true if a fresh key pair was created 87 * @return #GNUNET_OK on success (and only then is @a key_details set), 88 * #GNUNET_NO if an error response was already queued on 89 * @a connection, #GNUNET_SYSERR on hard failure 90 */ 91 enum GNUNET_GenericReturnValue 92 TMH_token_key_ensure ( 93 struct MHD_Connection *connection, 94 const char *instance_id, 95 const char *slug, 96 struct GNUNET_TIME_Timestamp valid_at, 97 struct GNUNET_TIME_Timestamp sign_until, 98 struct TALER_MERCHANTDB_TokenFamilyKeyDetails *key_details, 99 bool *minted); 100 101 102 /** 103 * Release all resources of @a key_details (but not the structure 104 * itself, which is typically stack-allocated). 105 * 106 * @param[in,out] key_details result of a successful 107 * #TMH_token_key_ensure() to release 108 */ 109 void 110 TMH_token_key_details_free ( 111 struct TALER_MERCHANTDB_TokenFamilyKeyDetails *key_details); 112 113 114 /** 115 * Current and future keys of a fountain grant, in order of strictly 116 * increasing expiry. Owns the key and family details. 117 */ 118 struct TMH_TokenKeyWindow 119 { 120 /** Keys selected using the shared order lookup and generation logic. */ 121 struct TALER_MERCHANTDB_TokenFamilyKeyDetails *keys; 122 123 /** Number of keys; at most key_window_size + 1. */ 124 unsigned int keys_len; 125 }; 126 127 128 /** 129 * Obtain the current key and up to @a key_window_size future keys. 130 * The first lookup is at max(now, family.valid_after); each subsequent 131 * lookup is one second beyond the previous key's actual expiry, capped 132 * at now + key_window_size * duration. No key may start after that 133 * horizon, including when the family itself starts in the future. 134 * Rounding can make the validity intervals overlap. Stop at the family 135 * expiry or when the existing validity rules cannot extend coverage. 136 * 137 * @param connection connection to report errors on 138 * @param instance_id instance owning the token family 139 * @param tf token family details 140 * @param now time of this request, also the private-key retention minimum 141 * @param key_window_size number of future keys, at most 142 * #TMH_MAX_FOUNTAIN_KEY_WINDOW (zero allows the current key only) 143 * @param[out] window initialized window; empty on error 144 * @return #GNUNET_OK on success (possibly an empty/shorter window), 145 * #GNUNET_NO if an error response was queued, 146 * #GNUNET_SYSERR on hard failure 147 */ 148 enum GNUNET_GenericReturnValue 149 TMH_token_key_window_get ( 150 struct MHD_Connection *connection, 151 const char *instance_id, 152 const struct TALER_MERCHANTDB_TokenFamilyDetails *tf, 153 struct GNUNET_TIME_Timestamp now, 154 unsigned int key_window_size, 155 struct TMH_TokenKeyWindow *window); 156 157 158 /** 159 * Release the window's keys and family details and reset it to empty. 160 * 161 * @param[in,out] window window to release 162 */ 163 void 164 TMH_token_key_window_free (struct TMH_TokenKeyWindow *window); 165 166 167 /** 168 * Select a key from an advertised window. An exact validity-start match 169 * takes precedence over overlapping earlier keys. Otherwise the first 170 * key covering @a valid_at is selected. A missing valid_at in the wallet 171 * request selects index zero directly, rather than calling this function. 172 * 173 * @param window current window of the grant 174 * @param valid_at requested validity time 175 * @param[out] key_index selected index 176 * @return #GNUNET_OK on match, #GNUNET_NO if outside the window 177 */ 178 enum GNUNET_GenericReturnValue 179 TMH_token_key_window_find ( 180 const struct TMH_TokenKeyWindow *window, 181 struct GNUNET_TIME_Timestamp valid_at, 182 unsigned int *key_index); 183 184 185 /** 186 * Convert token family details from the database into a contract 187 * token family (without keys). The result must be released via 188 * #TALER_MERCHANT_contract_token_family_free(). 189 * 190 * @param tf token family details from the database 191 * @param[out] family initialized contract token family 192 */ 193 void 194 TMH_token_family_to_contract ( 195 const struct TALER_MERCHANTDB_TokenFamilyDetails *tf, 196 struct TALER_MERCHANT_ContractTokenFamily *family); 197 198 #endif