donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 09ec169c848bdf66e1ea3bbab10df39082c529b8
parent 41854644ec2dcd21811c04be1f8e8a1e6ea2ae5e
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
Date:   Wed, 10 Apr 2024 00:28:09 +0200

work on issue receipts

Diffstat:
Msrc/donau/donau-httpd_keys.c | 21+++++++++++++++++----
Msrc/donau/donau-httpd_keys.h | 17+++++++++++++++++
Msrc/donau/donau-httpd_post-batch-issue.c | 36++++++++++++++++++++----------------
Msrc/include/donau_crypto_lib.h | 16----------------
Msrc/lib/donau_api_batch_issue_receipts.c | 2+-
Msrc/pq/pq_query_helper.c | 1230++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/testing/testing_api_cmd_issue_receipts.c | 9++++-----
Msrc/util/donau_signatures.c | 15---------------
8 files changed, 900 insertions(+), 446 deletions(-)

diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c @@ -1325,11 +1325,8 @@ DH_keys_donation_unit_by_hash ( { if (NULL == conn) return NULL; - // FIXME: server error or not found? - // *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn, - // h_denom_pub); *mret = TALER_MHD_reply_with_error (conn, - MHD_HTTP_INTERNAL_SERVER_ERROR, + MHD_HTTP_NOT_FOUND, TALER_EC_DONAU_GENERIC_KEYS_MISSING, NULL); return NULL; @@ -1337,5 +1334,21 @@ DH_keys_donation_unit_by_hash ( return dk; } +enum GNUNET_GenericReturnValue +DONAU_donation_unit_sign_blinded (struct DONAU_BlindedDonationUnitSignature *du_sig, + const struct DONAU_DonationUnitHashP *h_pub, + const struct DONAU_BlindedUniqueDonationIdentifier *budi) +{ + // FIXME: get private key from the hash of the public key... + const struct DONAU_DonationUnitPrivateKey *du_priv = {0}; + du_sig->blinded_sig + = GNUNET_CRYPTO_blind_sign (du_priv->bsign_priv_key, + /*for_melt ? "rm" :*/ "rw", + budi->blinded_message); + if (NULL == du_sig->blinded_sig) + return GNUNET_SYSERR; + return GNUNET_OK; +} + /* end of donau-httpd_keys.c */ diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h @@ -164,4 +164,21 @@ void DH_keys_finished (void); +/** + * Create blinded signature. + * + * @param[out] du_sig where to write the signature + * @param h_pub private key to use for signing + * @param budi the unique identifier already blinded + * @return #GNUNET_OK on success + */ +enum GNUNET_GenericReturnValue +DONAU_donation_unit_sign_blinded (struct + DONAU_BlindedDonationUnitSignature *du_sig, + const struct + DONAU_DonationUnitHashP *h_pub, + const struct + DONAU_BlindedUniqueDonationIdentifier *budi); + + #endif diff --git a/src/donau/donau-httpd_post-batch-issue.c b/src/donau/donau-httpd_post-batch-issue.c @@ -234,6 +234,7 @@ DH_handler_issue_receipts_post (struct DH_RequestContext *rc, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got charity from db!\n"); /* verify charity signature */ + // FIXME if (GNUNET_OK != DONAU_charity_budi_key_pair_verify (num_bkp, irc.bkp, &charity_meta.charity_pub, @@ -289,11 +290,11 @@ start: NULL); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "request have not been made yet (first time)!\n"); + "request has not been made yet (first time)!\n"); break; // it's the first request from the charity, we can proceed case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "request have been made already!\n"); + "request has been made already!\n"); signatures_to_JSON (num_bkp, check_receipts_meta.blinded_sig, blind_signatures); return TALER_MHD_REPLY_JSON_PACK ( @@ -308,25 +309,28 @@ start: { MHD_RESULT mret; struct DH_DonationUnitKey *dk; - dk = DH_keys_donation_unit_by_hash (&irc.bkp[i].h_donation_unit_pub, + // FIXME always public key not found + if (NULL == (dk = DH_keys_donation_unit_by_hash (&irc.bkp[i].h_donation_unit_pub, rc->connection, - &mret); - if (NULL == dk || 0 >= TALER_amount_add (&receipts_sum, &receipts_sum, - &dk->value)) - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "budikeypairs"); + &mret))) + return mret; + if (GNUNET_OK != TALER_check_currency(receipts_sum.currency)) + GNUNET_memcpy(receipts_sum.currency, dk->value.currency, sizeof(char) * TALER_CURRENCY_LEN); + GNUNET_assert (0 <= TALER_amount_add (&receipts_sum, &receipts_sum, + &dk->value)); } - struct TALER_Amount new_receipts_to_date = {0}; + struct TALER_Amount new_receipts_to_date; TALER_amount_add (&new_receipts_to_date, &receipts_sum, &charity_meta.receipts_to_date); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "new_receipts_to_date: %lu, receipts_sum: %lu, charity_max_per_year: %lu\n", + new_receipts_to_date.value, receipts_sum.value, charity_meta.max_per_year.value); // new_receipts_to_date has to be smaller or equal as max_per_year if (0 > TALER_amount_cmp (&new_receipts_to_date, &charity_meta.max_per_year)) return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED,// TODO: other EC - "budikeypairs"); + TALER_EC_DONAU_EXCEEDING_DONATION_LIMIT, + NULL); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "calculated the new receipts to date amount\n"); @@ -335,12 +339,12 @@ start: { for (size_t i = 0; i < num_bkp; i++) { - // TODO: get donation unit private key - const struct DONAU_DonationUnitPrivateKey du_priv; + // FIXME private key is missing + //const struct DONAU_DonationUnitPrivateKey du_priv; const struct DONAU_BlindedUniqueDonationIdentifier budi = irc.bkp[i]. blinded_udi; struct DONAU_BlindedDonationUnitSignature *du_sig = &du_sigs[i]; - if (GNUNET_SYSERR == TALER_donation_unit_sign_blinded (du_sig, &du_priv, & + if (GNUNET_SYSERR == DONAU_donation_unit_sign_blinded (du_sig, &irc.bkp[i].h_donation_unit_pub, & budi)) { GNUNET_break (0); diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h @@ -378,22 +378,6 @@ void DONAU_blinded_donation_unit_sig_free ( struct DONAU_BlindedDonationUnitSignature *donation_unit_sig); -/** - * Create blinded signature. - * - * @param[out] du_sig where to write the signature - * @param du_priv private key to use for signing - * @param budi the unique identifier already blinded - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -TALER_donation_unit_sign_blinded (struct - DONAU_BlindedDonationUnitSignature *du_sig, - const struct - DONAU_DonationUnitPrivateKey *du_priv, - const struct - DONAU_BlindedUniqueDonationIdentifier *budi); - /** * Verify signature made with a donation unit public key diff --git a/src/lib/donau_api_batch_issue_receipts.c b/src/lib/donau_api_batch_issue_receipts.c @@ -207,7 +207,7 @@ DONAU_charity_issue_receipt ( GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "signature or verification function(s) not ok\n"); } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "signature and verification functions ok\n"); TALER_LOG_DEBUG ("Connecting to the donau (%s)\n", url); diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c @@ -121,111 +121,563 @@ DONAU_PQ_query_param_donation_unit_pub ( return res; } +/** + * Closure for the array result specifications. Contains type information + * for the generic parser extract_array_generic and out-pointers for the results. + */ +struct ArrayResultCls +{ + /** + * Oid of the expected type, must match the oid in the header of the PQResult struct + */ + Oid oid; + + /** + * Target type + */ + //enum TALER_PQ_ArrayType typ; + + /** + * If not 0, defines the expected size of each entry + */ + size_t same_size; + + /** + * Out-pointer to write the number of elements in the array + */ + size_t *num; + + /** + * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0, + * allocate and put the array of @a num sizes here. NULL otherwise + */ + size_t **sizes; + + /** + * DB_connection, needed for OID-lookup for composite types + */ + const struct GNUNET_PQ_Context *db; + + /** + * Currency information for amount composites + */ + char currency[TALER_CURRENCY_LEN]; +}; -// FIXME: -// /** -// * Function to generate a typ specific query parameter and corresponding closure -// * -// * @param num Number of elements in @a elements -// * @param continuous If true, @a elements is an continuous array of data -// * @param elements Array of @a num elements, either continuous or pointers -// * @param sizes Array of @a num sizes, one per element, may be NULL -// * @param same_size If not 0, all elements in @a elements have this size -// * @param typ Supported internal type of each element in @a elements -// * @param oid Oid of the type to be used in Postgres -// * @param[in,out] db our database handle for looking up OIDs -// * @return Query parameter -// */ -// static struct GNUNET_PQ_QueryParam -// query_param_array_generic ( -// unsigned int num, -// bool continuous, -// const void *elements, -// const size_t *sizes, -// size_t same_size, -// enum TALER_PQ_ArrayType typ, -// Oid oid, -// struct GNUNET_PQ_Context *db) -// { -// struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls); - -// meta->typ = typ; -// meta->oid = oid; -// meta->sizes = sizes; -// meta->same_size = same_size; -// meta->continuous = continuous; -// meta->db = db; - -// { -// struct GNUNET_PQ_QueryParam res = { -// .conv = qconv_array, -// .conv_cls = meta, -// .conv_cls_cleanup = qconv_array_cls_cleanup, -// .data = elements, -// .size = num, -// .num_params = 1, -// }; - -// return res; -// } -// } - -// struct GNUNET_PQ_QueryParam -// DONAU_PQ_query_param_array_blinded_donation_unit_sig ( -// size_t num, -// const struct DONAU_BlindedDonationUnitSignature *du_sigs, -// struct GNUNET_PQ_Context *db) -// { -// Oid oid; - -// GNUNET_assert (GNUNET_OK == -// GNUNET_PQ_get_oid_by_name (db, -// "bytea", -// &oid)); -// return query_param_array_generic (num, -// true, -// du_sigs, -// NULL, -// 0, -// TALER_PQ_array_of_blinded_denom_sig, -// oid, -// NULL); -// } - -// /** -// * Extract data from a Postgres database @a result as array of a specific type -// * from row @a row. The type information and optionally additional -// * out-parameters are given in @a cls which is of type array_result_cls. -// * -// * @param cls closure of type array_result_cls -// * @param result where to extract data from -// * @param row row to extract data from -// * @param fname name (or prefix) of the fields to extract from -// * @param[in,out] dst_size where to store size of result, may be NULL -// * @param[out] dst where to store the result -// * @return -// * #GNUNET_YES if all results could be extracted -// * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) -// */ -// static enum GNUNET_GenericReturnValue -// extract_array_generic ( -// void *cls, -// PGresult *result, -// int row, -// const char *fname, -// size_t *dst_size, -// void *dst) -// { -// const struct ArrayResultCls *info = cls; -// int data_sz; -// char *data; -// void *out = NULL; -// struct GNUNET_PQ_ArrayHeader_P header; -// int col_num; - -// GNUNET_assert (NULL != dst); -// *((void **) dst) = NULL; /** + * Closure for the array type handlers. + * + * May contain sizes information for the data, given (and handled) by the + * caller. + */ +struct qconv_array_cls +{ + /** + * If not null, contains the array of sizes (the size of the array is the + * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free + * this memory. + * + * If not null, this value has precedence over @a sizes, which MUST be NULL */ + const size_t *sizes; + + /** + * If @a size and @a c_sizes are NULL, this field defines the same size + * for each element in the array. + */ + size_t same_size; + + /** + * If true, the array parameter to the data pointer to the qconv_array is a + * continuous byte array of data, either with @a same_size each or sizes + * provided bytes by @a sizes; + */ + bool continuous; + + /** + * Type of the array elements + */ + //enum TALER_PQ_ArrayType typ; + + /** + * Oid of the array elements + */ + Oid oid; + + /** + * db context, needed for OID-lookup of basis-types + */ + struct GNUNET_PQ_Context *db; +}; + +/** + * Function called to convert input argument into SQL parameters for arrays + * + * Note: the format for the encoding of arrays for libpq is not very well + * documented. We peeked into various sources (postgresql and libpqtypes) for + * guidance. + * + * @param cls Closure of type struct qconv_array_cls* + * @param data Pointer to first element in the array + * @param data_len Number of _elements_ in array @a data (if applicable) + * @param[out] param_values SQL data to set + * @param[out] param_lengths SQL length data to set + * @param[out] param_formats SQL format data to set + * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays + * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() + * @param scratch_length number of entries left in @a scratch + * @return -1 on error, number of offsets used in @a scratch otherwise + */ +static int +qconv_array ( + void *cls, + const void *data, + size_t data_len, + void *param_values[], + int param_lengths[], + int param_formats[], + unsigned int param_length, + void *scratch[], + unsigned int scratch_length) +{ + struct qconv_array_cls *meta = cls; + size_t num = data_len; + size_t total_size; + const size_t *sizes; + bool same_sized; + void *elements = NULL; + bool noerror = true; + /* needed to capture the encoded rsa signatures */ + void **buffers = NULL; + size_t *buffer_lengths = NULL; + + (void) (param_length); + (void) (scratch_length); + + GNUNET_assert (NULL != meta); + GNUNET_assert (num < INT_MAX); + + sizes = meta->sizes; + same_sized = (0 != meta->same_size); + +#define RETURN_UNLESS(cond) \ + do { \ + if (! (cond)) \ + { \ + GNUNET_break ((cond)); \ + noerror = false; \ + goto DONE; \ + } \ + } while (0) + + /* Calculate sizes and check bounds */ + { + /* num * length-field */ + size_t x = sizeof(uint32_t); + size_t y = x * num; + RETURN_UNLESS ((0 == num) || (y / num == x)); + + /* size of header */ + total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P); + total_size += y; + RETURN_UNLESS (total_size >= x); + + /* sizes of elements */ + if (same_sized) + { + x = num * meta->same_size; + RETURN_UNLESS ((0 == num) || (x / num == meta->same_size)); + + y = total_size; + total_size += x; + RETURN_UNLESS (total_size >= y); + } + else /* sizes are different per element */ + { + // switch (meta->typ) + // { + // case TALER_PQ_array_of_amount_currency: + // { + // const struct TALER_Amount *amounts = data; + // Oid oid_v; + // Oid oid_f; + // Oid oid_c; + + // buffer_lengths = GNUNET_new_array (num, size_t); + // /* hoist out of loop? */ + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "int8", + // &oid_v)); + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "int4", + // &oid_f)); + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "varchar", + // &oid_c)); + // for (size_t i = 0; i<num; i++) + // { + // struct TALER_PQ_AmountCurrencyP am; + // size_t len; + + // len = TALER_PQ_make_taler_pq_amount_currency_ ( + // &amounts[i], + // oid_v, + // oid_f, + // oid_c, + // &am); + // buffer_lengths[i] = len; + // y = total_size; + // total_size += len; + // RETURN_UNLESS (total_size >= y); + // } + // sizes = buffer_lengths; + // break; + // } + // case TALER_PQ_array_of_blinded_denom_sig: + // { + const struct DONAU_BlindedDonationUnitSignature *du_sigs = data; + size_t len; + + buffers = GNUNET_new_array (num, void *); + buffer_lengths = GNUNET_new_array (num, size_t); + + for (size_t i = 0; i<num; i++) + { + const struct GNUNET_CRYPTO_BlindedSignature *bs = + du_sigs[i].blinded_sig; + + switch (bs->cipher) + { + case GNUNET_CRYPTO_BSA_RSA: + len = GNUNET_CRYPTO_rsa_signature_encode ( + bs->details.blinded_rsa_signature, + &buffers[i]); + RETURN_UNLESS (len != 0); + break; + case GNUNET_CRYPTO_BSA_CS: + len = sizeof (bs->details.blinded_cs_answer); + break; + default: + GNUNET_assert (0); + } + + /* for the cipher and marker */ + len += 2 * sizeof(uint32_t); + buffer_lengths[i] = len; + + y = total_size; + total_size += len; + RETURN_UNLESS (total_size >= y); + } + sizes = buffer_lengths; + // break; + // } + // default: + // GNUNET_assert (0); + // } + } + + RETURN_UNLESS (INT_MAX > total_size); + RETURN_UNLESS (0 != total_size); + + elements = GNUNET_malloc (total_size); + } + + /* Write data */ + { + char *out = elements; + struct GNUNET_PQ_ArrayHeader_P h = { + .ndim = htonl (1), /* We only support one-dimensional arrays */ + .has_null = htonl (0), /* We do not support NULL entries in arrays */ + .lbound = htonl (1), /* Default start index value */ + .dim = htonl (num), + .oid = htonl (meta->oid), + }; + + /* Write header */ + GNUNET_memcpy (out, + &h, + sizeof(h)); + out += sizeof(h); + + /* Write elements */ + for (size_t i = 0; i < num; i++) + { + size_t sz = same_sized ? meta->same_size : sizes[i]; + + *(uint32_t *) out = htonl (sz); + out += sizeof(uint32_t); + // switch (meta->typ) + // { + // case TALER_PQ_array_of_amount: + // { + // const struct TALER_Amount *amounts = data; + // Oid oid_v; + // Oid oid_f; + + // /* hoist out of loop? */ + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "int8", + // &oid_v)); + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "int4", + // &oid_f)); + // { + // struct TALER_PQ_AmountP am + // = TALER_PQ_make_taler_pq_amount_ ( + // &amounts[i], + // oid_v, + // oid_f); + + // GNUNET_memcpy (out, + // &am, + // sizeof(am)); + // } + // break; + // } + // case TALER_PQ_array_of_amount_currency: + // { + // const struct TALER_Amount *amounts = data; + // Oid oid_v; + // Oid oid_f; + // Oid oid_c; + + // /* hoist out of loop? */ + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "int8", + // &oid_v)); + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "int4", + // &oid_f)); + // GNUNET_assert (GNUNET_OK == + // GNUNET_PQ_get_oid_by_name (meta->db, + // "varchar", + // &oid_c)); + // { + // struct TALER_PQ_AmountCurrencyP am; + // size_t len; + + // len = TALER_PQ_make_taler_pq_amount_currency_ ( + // &amounts[i], + // oid_v, + // oid_f, + // oid_c, + // &am); + // GNUNET_memcpy (out, + // &am, + // len); + // } + // break; + // } + // case TALER_PQ_array_of_blinded_denom_sig: + // { + const struct DONAU_BlindedDonationUnitSignature *denom_sigs = data; + const struct GNUNET_CRYPTO_BlindedSignature *bs = + denom_sigs[i].blinded_sig; + uint32_t be[2]; + + be[0] = htonl ((uint32_t) bs->cipher); + be[1] = htonl (0x01); /* magic margker: blinded */ + GNUNET_memcpy (out, + &be, + sizeof(be)); + out += sizeof(be); + sz -= sizeof(be); + + switch (bs->cipher) + { + case GNUNET_CRYPTO_BSA_RSA: + /* For RSA, 'same_sized' must have been false */ + GNUNET_assert (NULL != buffers); + GNUNET_memcpy (out, + buffers[i], + sz); + break; + case GNUNET_CRYPTO_BSA_CS: + GNUNET_memcpy (out, + &bs->details.blinded_cs_answer, + sz); + break; + default: + GNUNET_assert (0); + } + // break; + // } + // case TALER_PQ_array_of_blinded_coin_hash: + // { + // const struct TALER_BlindedCoinHashP *coin_hs = data; + + // GNUNET_memcpy (out, + // &coin_hs[i], + // sizeof(struct TALER_BlindedCoinHashP)); + + // break; + // } + // case TALER_PQ_array_of_denom_hash: + // { + // const struct TALER_DenominationHashP *denom_hs = data; + + // GNUNET_memcpy (out, + // &denom_hs[i], + // sizeof(struct TALER_DenominationHashP)); + // break; + // } + // case TALER_PQ_array_of_hash_code: + // { + // const struct GNUNET_HashCode *hashes = data; + + // GNUNET_memcpy (out, + // &hashes[i], + // sizeof(struct GNUNET_HashCode)); + // break; + // } + // default: + // { + // GNUNET_assert (0); + // break; + // } + // } + out += sz; + } + } + param_values[0] = elements; + param_lengths[0] = total_size; + param_formats[0] = 1; + scratch[0] = elements; + +DONE: + if (NULL != buffers) + { + for (size_t i = 0; i<num; i++) + GNUNET_free (buffers[i]); + GNUNET_free (buffers); + } + GNUNET_free (buffer_lengths); + if (noerror) + return 1; + return -1; +} + + +/** + * Callback to cleanup a qconv_array_cls to be used during + * GNUNET_PQ_cleanup_query_params_closures + */ +static void +qconv_array_cls_cleanup (void *cls) +{ + GNUNET_free (cls); +} + +/** + * Function to generate a typ specific query parameter and corresponding closure + * + * @param num Number of elements in @a elements + * @param continuous If true, @a elements is an continuous array of data + * @param elements Array of @a num elements, either continuous or pointers + * @param sizes Array of @a num sizes, one per element, may be NULL + * @param same_size If not 0, all elements in @a elements have this size + * @param typ Supported internal type of each element in @a elements + * @param oid Oid of the type to be used in Postgres + * @param[in,out] db our database handle for looking up OIDs + * @return Query parameter + */ +static struct GNUNET_PQ_QueryParam +query_param_array_generic ( + unsigned int num, + bool continuous, + const void *elements, + const size_t *sizes, + size_t same_size, + //enum TALER_PQ_ArrayType typ, + Oid oid, + struct GNUNET_PQ_Context *db) +{ + struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls); + + //meta->typ = typ; + meta->oid = oid; + meta->sizes = sizes; + meta->same_size = same_size; + meta->continuous = continuous; + meta->db = db; + + { + struct GNUNET_PQ_QueryParam res = { + .conv = qconv_array, + .conv_cls = meta, + .conv_cls_cleanup = qconv_array_cls_cleanup, + .data = elements, + .size = num, + .num_params = 1, + }; + + return res; + } +} + +struct GNUNET_PQ_QueryParam +DONAU_PQ_query_param_array_blinded_donation_unit_sig ( + size_t num, + const struct DONAU_BlindedDonationUnitSignature *du_sigs, + struct GNUNET_PQ_Context *db) +{ + Oid oid; + + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "bytea", + &oid)); + return query_param_array_generic (num, + true, + du_sigs, + NULL, + 0, + //TALER_PQ_array_of_blinded_du_sig, + oid, + NULL); +} + +/** + * Extract data from a Postgres database @a result as array of a specific type + * from row @a row. The type information and optionally additional + * out-parameters are given in @a cls which is of type array_result_cls. + * + * @param cls closure of type array_result_cls + * @param result where to extract data from + * @param row row to extract data from + * @param fname name (or prefix) of the fields to extract from + * @param[in,out] dst_size where to store size of result, may be NULL + * @param[out] dst where to store the result + * @return + * #GNUNET_YES if all results could be extracted + * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) + */ +static enum GNUNET_GenericReturnValue +extract_array_generic ( + void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + const struct ArrayResultCls *info = cls; + int data_sz; + char *data; + //void *out = NULL; + struct GNUNET_PQ_ArrayHeader_P header; + int col_num; + + GNUNET_assert (NULL != dst); + *((void **) dst) = NULL; + #define FAIL_IF(cond) \ do { \ if ((cond)) \ @@ -234,291 +686,291 @@ DONAU_PQ_query_param_donation_unit_pub ( goto FAIL; \ } \ } while (0) -**/ -// col_num = PQfnumber (result, fname); -// FAIL_IF (0 > col_num); - -// data_sz = PQgetlength (result, row, col_num); -// FAIL_IF (0 > data_sz); -// FAIL_IF (sizeof(header) > (size_t) data_sz); - -// data = PQgetvalue (result, row, col_num); -// FAIL_IF (NULL == data); - -// { -// struct GNUNET_PQ_ArrayHeader_P *h = -// (struct GNUNET_PQ_ArrayHeader_P *) data; - -// header.ndim = ntohl (h->ndim); -// header.has_null = ntohl (h->has_null); -// header.oid = ntohl (h->oid); -// header.dim = ntohl (h->dim); -// header.lbound = ntohl (h->lbound); - -// FAIL_IF (1 != header.ndim); -// FAIL_IF (INT_MAX <= header.dim); -// FAIL_IF (0 != header.has_null); -// FAIL_IF (1 != header.lbound); -// FAIL_IF (info->oid != header.oid); -// } - -// if (NULL != info->num) -// *info->num = header.dim; - -// { -// char *in = data + sizeof(header); - -// switch (info->typ) -// { -// case TALER_PQ_array_of_amount: -// { -// struct TALER_Amount *amounts; -// if (NULL != dst_size) -// *dst_size = sizeof(struct TALER_Amount) * (header.dim); - -// amounts = GNUNET_new_array (header.dim, -// struct TALER_Amount); -// *((void **) dst) = amounts; - -// for (uint32_t i = 0; i < header.dim; i++) -// { -// struct TALER_PQ_AmountP ap; -// struct TALER_Amount *amount = &amounts[i]; -// uint32_t val; -// size_t sz; - -// GNUNET_memcpy (&val, -// in, -// sizeof(val)); -// sz = ntohl (val); -// in += sizeof(val); - -// /* total size for this array-entry */ -// FAIL_IF (sizeof(ap) != sz); - -// GNUNET_memcpy (&ap, -// in, -// sz); -// FAIL_IF (2 != ntohl (ap.cnt)); - -// amount->value = GNUNET_ntohll (ap.v); -// amount->fraction = ntohl (ap.f); -// GNUNET_memcpy (amount->currency, -// info->currency, -// TALER_CURRENCY_LEN); - -// in += sizeof(struct TALER_PQ_AmountP); -// } -// return GNUNET_OK; -// } -// case TALER_PQ_array_of_denom_hash: -// if (NULL != dst_size) -// *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim); -// out = GNUNET_new_array (header.dim, -// struct TALER_DenominationHashP); -// *((void **) dst) = out; -// for (uint32_t i = 0; i < header.dim; i++) -// { -// uint32_t val; -// size_t sz; - -// GNUNET_memcpy (&val, -// in, -// sizeof(val)); -// sz = ntohl (val); -// FAIL_IF (sz != sizeof(struct TALER_DenominationHashP)); -// in += sizeof(uint32_t); -// *(struct TALER_DenominationHashP *) out = -// *(struct TALER_DenominationHashP *) in; -// in += sz; -// out += sz; -// } -// return GNUNET_OK; - -// case TALER_PQ_array_of_hash_code: -// if (NULL != dst_size) -// *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim); -// out = GNUNET_new_array (header.dim, -// struct GNUNET_HashCode); -// *((void **) dst) = out; -// for (uint32_t i = 0; i < header.dim; i++) -// { -// uint32_t val; -// size_t sz; - -// GNUNET_memcpy (&val, -// in, -// sizeof(val)); -// sz = ntohl (val); -// FAIL_IF (sz != sizeof(struct GNUNET_HashCode)); -// in += sizeof(uint32_t); -// *(struct GNUNET_HashCode *) out = -// *(struct GNUNET_HashCode *) in; -// in += sz; -// out += sz; -// } -// return GNUNET_OK; - -// case TALER_PQ_array_of_blinded_coin_hash: -// if (NULL != dst_size) -// *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim); -// out = GNUNET_new_array (header.dim, -// struct TALER_BlindedCoinHashP); -// *((void **) dst) = out; -// for (uint32_t i = 0; i < header.dim; i++) -// { -// uint32_t val; -// size_t sz; - -// GNUNET_memcpy (&val, -// in, -// sizeof(val)); -// sz = ntohl (val); -// FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP)); -// in += sizeof(uint32_t); -// *(struct TALER_BlindedCoinHashP *) out = -// *(struct TALER_BlindedCoinHashP *) in; -// in += sz; -// out += sz; -// } -// return GNUNET_OK; - -// case TALER_PQ_array_of_blinded_denom_sig: -// { -// struct TALER_BlindedDenominationSignature *denom_sigs; -// if (0 == header.dim) -// { -// if (NULL != dst_size) -// *dst_size = 0; -// break; -// } - -// denom_sigs = GNUNET_new_array (header.dim, -// struct TALER_BlindedDenominationSignature); -// *((void **) dst) = denom_sigs; - -// /* copy data */ -// for (uint32_t i = 0; i < header.dim; i++) -// { -// struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i]; -// struct GNUNET_CRYPTO_BlindedSignature *bs; -// uint32_t be[2]; -// uint32_t val; -// size_t sz; - -// GNUNET_memcpy (&val, -// in, -// sizeof(val)); -// sz = ntohl (val); -// FAIL_IF (sizeof(be) > sz); - -// in += sizeof(val); -// GNUNET_memcpy (&be, -// in, -// sizeof(be)); -// FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */ - -// in += sizeof(be); -// sz -= sizeof(be); -// bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); -// bs->cipher = ntohl (be[0]); -// bs->rc = 1; -// switch (bs->cipher) -// { -// case GNUNET_CRYPTO_BSA_RSA: -// bs->details.blinded_rsa_signature -// = GNUNET_CRYPTO_rsa_signature_decode (in, -// sz); -// if (NULL == bs->details.blinded_rsa_signature) -// { -// GNUNET_free (bs); -// FAIL_IF (true); -// } -// break; -// case GNUNET_CRYPTO_BSA_CS: -// if (sizeof(bs->details.blinded_cs_answer) != sz) -// { -// GNUNET_free (bs); -// FAIL_IF (true); -// } -// GNUNET_memcpy (&bs->details.blinded_cs_answer, -// in, -// sz); -// break; -// default: -// GNUNET_free (bs); -// FAIL_IF (true); -// } -// denom_sig->blinded_sig = bs; -// in += sz; -// } -// return GNUNET_OK; -// } -// default: -// FAIL_IF (true); -// } -// } -// FAIL: -// GNUNET_free (*(void **) dst); -// return GNUNET_SYSERR; -// #undef FAIL_IF -// } - - -// /** -// * Cleanup of the data and closure of an array spec. -// */ -// static void -// array_cleanup (void *cls, -// void *rd) -// { -// struct ArrayResultCls *info = cls; -// void **dst = rd; - -// if ((0 == info->same_size) && -// (NULL != info->sizes)) -// GNUNET_free (*(info->sizes)); - -// /* Clean up signatures, if applicable */ -// if (TALER_PQ_array_of_blinded_denom_sig == info->typ) -// { -// struct TALER_BlindedDenominationSignature *denom_sigs = *dst; -// GNUNET_assert (NULL != info->num); -// for (size_t i = 0; i < *info->num; i++) -// GNUNET_free (denom_sigs[i].blinded_sig); -// } - -// GNUNET_free (cls); -// GNUNET_free (*dst); -// *dst = NULL; -// } - - -// struct GNUNET_PQ_ResultSpec -// DONAU_PQ_result_spec_array_blinded_donation_unit_sig ( -// struct GNUNET_PQ_Context *db, -// const char *name, -// size_t *num, -// struct DONAU_BlindedDonationUnitSignature **du_sigs) -// { -// struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); - -// info->num = num; -// info->typ = TALER_PQ_array_of_blinded_denom_sig; -// GNUNET_assert (GNUNET_OK == -// GNUNET_PQ_get_oid_by_name (db, -// "bytea", -// &info->oid)); - -// struct GNUNET_PQ_ResultSpec res = { -// .conv = extract_array_generic, -// .cleaner = array_cleanup, -// .dst = (void *) du_sigs, -// .fname = name, -// .cls = info -// }; -// return res; - -// } + + col_num = PQfnumber (result, fname); + FAIL_IF (0 > col_num); + + data_sz = PQgetlength (result, row, col_num); + FAIL_IF (0 > data_sz); + FAIL_IF (sizeof(header) > (size_t) data_sz); + + data = PQgetvalue (result, row, col_num); + FAIL_IF (NULL == data); + + { + struct GNUNET_PQ_ArrayHeader_P *h = + (struct GNUNET_PQ_ArrayHeader_P *) data; + + header.ndim = ntohl (h->ndim); + header.has_null = ntohl (h->has_null); + header.oid = ntohl (h->oid); + header.dim = ntohl (h->dim); + header.lbound = ntohl (h->lbound); + + FAIL_IF (1 != header.ndim); + FAIL_IF (INT_MAX <= header.dim); + FAIL_IF (0 != header.has_null); + FAIL_IF (1 != header.lbound); + FAIL_IF (info->oid != header.oid); + } + + if (NULL != info->num) + *info->num = header.dim; + + { + char *in = data + sizeof(header); + + // switch (info->typ) + // { + // case TALER_PQ_array_of_amount: + // { + // struct TALER_Amount *amounts; + // if (NULL != dst_size) + // *dst_size = sizeof(struct TALER_Amount) * (header.dim); + + // amounts = GNUNET_new_array (header.dim, + // struct TALER_Amount); + // *((void **) dst) = amounts; + + // for (uint32_t i = 0; i < header.dim; i++) + // { + // struct TALER_PQ_AmountP ap; + // struct TALER_Amount *amount = &amounts[i]; + // uint32_t val; + // size_t sz; + + // GNUNET_memcpy (&val, + // in, + // sizeof(val)); + // sz = ntohl (val); + // in += sizeof(val); + + // /* total size for this array-entry */ + // FAIL_IF (sizeof(ap) != sz); + + // GNUNET_memcpy (&ap, + // in, + // sz); + // FAIL_IF (2 != ntohl (ap.cnt)); + + // amount->value = GNUNET_ntohll (ap.v); + // amount->fraction = ntohl (ap.f); + // GNUNET_memcpy (amount->currency, + // info->currency, + // TALER_CURRENCY_LEN); + + // in += sizeof(struct TALER_PQ_AmountP); + // } + // return GNUNET_OK; + // } + // case TALER_PQ_array_of_denom_hash: + // if (NULL != dst_size) + // *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim); + // out = GNUNET_new_array (header.dim, + // struct TALER_DenominationHashP); + // *((void **) dst) = out; + // for (uint32_t i = 0; i < header.dim; i++) + // { + // uint32_t val; + // size_t sz; + + // GNUNET_memcpy (&val, + // in, + // sizeof(val)); + // sz = ntohl (val); + // FAIL_IF (sz != sizeof(struct TALER_DenominationHashP)); + // in += sizeof(uint32_t); + // *(struct TALER_DenominationHashP *) out = + // *(struct TALER_DenominationHashP *) in; + // in += sz; + // out += sz; + // } + // return GNUNET_OK; + + // case TALER_PQ_array_of_hash_code: + // if (NULL != dst_size) + // *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim); + // out = GNUNET_new_array (header.dim, + // struct GNUNET_HashCode); + // *((void **) dst) = out; + // for (uint32_t i = 0; i < header.dim; i++) + // { + // uint32_t val; + // size_t sz; + + // GNUNET_memcpy (&val, + // in, + // sizeof(val)); + // sz = ntohl (val); + // FAIL_IF (sz != sizeof(struct GNUNET_HashCode)); + // in += sizeof(uint32_t); + // *(struct GNUNET_HashCode *) out = + // *(struct GNUNET_HashCode *) in; + // in += sz; + // out += sz; + // } + // return GNUNET_OK; + + // case TALER_PQ_array_of_blinded_coin_hash: + // if (NULL != dst_size) + // *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim); + // out = GNUNET_new_array (header.dim, + // struct TALER_BlindedCoinHashP); + // *((void **) dst) = out; + // for (uint32_t i = 0; i < header.dim; i++) + // { + // uint32_t val; + // size_t sz; + + // GNUNET_memcpy (&val, + // in, + // sizeof(val)); + // sz = ntohl (val); + // FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP)); + // in += sizeof(uint32_t); + // *(struct TALER_BlindedCoinHashP *) out = + // *(struct TALER_BlindedCoinHashP *) in; + // in += sz; + // out += sz; + // } + // return GNUNET_OK; + + // case TALER_PQ_array_of_blinded_denom_sig: + // { + struct DONAU_BlindedDonationUnitSignature *du_sigs; + if (0 == header.dim) + { + if (NULL != dst_size) + *dst_size = 0; + goto FAIL; + } + + du_sigs = GNUNET_new_array (header.dim, + struct DONAU_BlindedDonationUnitSignature); + *((void **) dst) = du_sigs; + + /* copy data */ + for (uint32_t i = 0; i < header.dim; i++) + { + struct DONAU_BlindedDonationUnitSignature *du_sig = &du_sigs[i]; + struct GNUNET_CRYPTO_BlindedSignature *bs; + uint32_t be[2]; + uint32_t val; + size_t sz; + + GNUNET_memcpy (&val, + in, + sizeof(val)); + sz = ntohl (val); + FAIL_IF (sizeof(be) > sz); + + in += sizeof(val); + GNUNET_memcpy (&be, + in, + sizeof(be)); + FAIL_IF (0x01 != ntohl (be[1])); /* magic marker: blinded */ + + in += sizeof(be); + sz -= sizeof(be); + bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + bs->cipher = ntohl (be[0]); + bs->rc = 1; + switch (bs->cipher) + { + case GNUNET_CRYPTO_BSA_RSA: + bs->details.blinded_rsa_signature + = GNUNET_CRYPTO_rsa_signature_decode (in, + sz); + if (NULL == bs->details.blinded_rsa_signature) + { + GNUNET_free (bs); + FAIL_IF (true); + } + break; + case GNUNET_CRYPTO_BSA_CS: + if (sizeof(bs->details.blinded_cs_answer) != sz) + { + GNUNET_free (bs); + FAIL_IF (true); + } + GNUNET_memcpy (&bs->details.blinded_cs_answer, + in, + sz); + break; + default: + GNUNET_free (bs); + FAIL_IF (true); + } + du_sig->blinded_sig = bs; + in += sz; + } + return GNUNET_OK; + // } + // default: + // FAIL_IF (true); + // } + } +FAIL: + GNUNET_free (*(void **) dst); + return GNUNET_SYSERR; +#undef FAIL_IF +} + + +/** + * Cleanup of the data and closure of an array spec. + */ +static void +array_cleanup (void *cls, + void *rd) +{ + struct ArrayResultCls *info = cls; + void **dst = rd; + + if ((0 == info->same_size) && + (NULL != info->sizes)) + GNUNET_free (*(info->sizes)); + + /* Clean up signatures, if applicable */ + // if (TALER_PQ_array_of_blinded_denom_sig == info->typ) + // { + struct DONAU_BlindedDonationUnitSignature *du_sigs = *dst; + GNUNET_assert (NULL != info->num); + for (size_t i = 0; i < *info->num; i++) + GNUNET_free (du_sigs[i].blinded_sig); + // } + + GNUNET_free (cls); + GNUNET_free (*dst); + *dst = NULL; +} + + +struct GNUNET_PQ_ResultSpec +DONAU_PQ_result_spec_array_blinded_donation_unit_sig ( + struct GNUNET_PQ_Context *db, + const char *name, + size_t *num, + struct DONAU_BlindedDonationUnitSignature **du_sigs) +{ + struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls); + + info->num = num; + // info->typ = TALER_PQ_array_of_blinded_denom_sig; + GNUNET_assert (GNUNET_OK == + GNUNET_PQ_get_oid_by_name (db, + "bytea", + &info->oid)); + + struct GNUNET_PQ_ResultSpec res = { + .conv = extract_array_generic, + .cleaner = array_cleanup, + .dst = (void *) du_sigs, + .fname = name, + .cls = info + }; + return res; + +} /* end of pq/pq_query_helper.c */ diff --git a/src/testing/testing_api_cmd_issue_receipts.c b/src/testing/testing_api_cmd_issue_receipts.c @@ -99,6 +99,8 @@ issue_receipts_status_cb (void *cls, { struct StatusState *ss = cls; + // TODO: use the public donation unit keysZZZZZ from the DONAU to verify the signatures + ss->birh = NULL; if (ss->expected_response_code != biresp->hr.http_status) { @@ -113,8 +115,7 @@ issue_receipts_status_cb (void *cls, TALER_TESTING_interpreter_fail (ss->is); return; } - // if (ss->expected_response_code == biresp->hr.http_status) - // ss->charity_id = (unsigned long long) biresp->details.ok.charity_id; + TALER_TESTING_interpreter_next (ss->is); } @@ -179,15 +180,13 @@ status_run (void *cls, ss->keys = keys; } - // TODO: build bkps with traits from /keys request, use the public sign key from the - // DONAU to verify the signatures ss->bkps = GNUNET_new_array (ss->num_bkp, struct DONAU_BlindedUniqueDonationIdentifierKeyPair); for (size_t cnt = 0; cnt < ss->num_bkp; cnt++) { struct GNUNET_CRYPTO_RsaBlindedMessage *rp; - struct DONAU_BlindedUniqueDonationIdentifier *bp; + struct DONAU_BlindedUniqueDonationIdentifier *bp = {0}; DONAU_donation_unit_pub_hash (&ss->keys->donation_unit_keys[0].key, &ss->bkps[cnt].h_donation_unit_pub); bp = &ss->bkps[cnt].blinded_udi; diff --git a/src/util/donau_signatures.c b/src/util/donau_signatures.c @@ -110,19 +110,4 @@ DONAU_donation_statement_verify ( &donau_pub->eddsa_pub); } - -enum GNUNET_GenericReturnValue -TALER_donation_unit_sign_blinded (struct DONAU_BlindedDonationUnitSignature *du_sig, - const struct DONAU_DonationUnitPrivateKey *du_priv, - const struct DONAU_BlindedUniqueDonationIdentifier *budi) -{ - du_sig->blinded_sig - = GNUNET_CRYPTO_blind_sign (du_priv->bsign_priv_key, - /*for_melt ? "rm" :*/ "rw", - budi->blinded_message); - if (NULL == du_sig->blinded_sig) - return GNUNET_SYSERR; - return GNUNET_OK; -} - /* end of donau_signatures.c */