pq_query_helper.c (35012B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU 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 General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file pq/pq_query_helper.c 18 * @brief helper functions for Taler-specific libpq (PostGres) interactions 19 * @author Sree Harsha Totakura <sreeharsha@totakura.in> 20 * @author Florian Dold 21 * @author Christian Grothoff 22 */ 23 #include "taler/platform.h" 24 #include <gnunet/gnunet_common.h> 25 #include <gnunet/gnunet_util_lib.h> 26 #include <gnunet/gnunet_pq_lib.h> 27 #include "taler/taler_pq_lib.h" 28 #include "pq_common.h" 29 30 31 /** 32 * Function called to convert input amount into SQL parameter as tuple. 33 * 34 * @param cls closure 35 * @param data pointer to input argument, here a `struct TALER_Amount` 36 * @param data_len number of bytes in @a data (if applicable) 37 * @param[out] param_values SQL data to set 38 * @param[out] param_lengths SQL length data to set 39 * @param[out] param_formats SQL format data to set 40 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 41 * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc() 42 * @param scratch_length number of entries left in @a scratch 43 * @return -1 on error, number of offsets used in @a scratch otherwise 44 */ 45 static int 46 qconv_amount_currency_tuple (void *cls, 47 const void *data, 48 size_t data_len, 49 void *param_values[], 50 int param_lengths[], 51 int param_formats[], 52 unsigned int param_length, 53 void *scratch[], 54 unsigned int scratch_length) 55 { 56 struct GNUNET_PQ_Context *db = cls; 57 const struct TALER_Amount *amount = data; 58 size_t sz; 59 60 GNUNET_assert (NULL != db); 61 GNUNET_assert (NULL != amount); 62 GNUNET_assert (1 == param_length); 63 GNUNET_assert (1 <= scratch_length); 64 GNUNET_assert (sizeof (struct TALER_Amount) == data_len); 65 GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid)); 66 { 67 char *out; 68 Oid oid_v; 69 Oid oid_f; 70 Oid oid_c; 71 struct TALER_PQ_AmountCurrencyP d; 72 73 GNUNET_assert (GNUNET_OK == 74 GNUNET_PQ_get_oid_by_name (db, 75 "int8", 76 &oid_v)); 77 GNUNET_assert (GNUNET_OK == 78 GNUNET_PQ_get_oid_by_name (db, 79 "int4", 80 &oid_f)); 81 GNUNET_assert (GNUNET_OK == 82 GNUNET_PQ_get_oid_by_name (db, 83 "varchar", 84 &oid_c)); 85 sz = TALER_PQ_make_taler_pq_amount_currency_ (amount, 86 oid_v, 87 oid_f, 88 oid_c, 89 &d); 90 out = GNUNET_malloc (sz); 91 memcpy (out, 92 &d, 93 sz); 94 scratch[0] = out; 95 } 96 97 param_values[0] = scratch[0]; 98 param_lengths[0] = sz; 99 param_formats[0] = 1; 100 101 return 1; 102 } 103 104 105 struct GNUNET_PQ_QueryParam 106 TALER_PQ_query_param_amount_with_currency ( 107 const struct GNUNET_PQ_Context *db, 108 const struct TALER_Amount *amount) 109 { 110 struct GNUNET_PQ_QueryParam res = { 111 .conv_cls = (void *) db, 112 .conv = &qconv_amount_currency_tuple, 113 .data = amount, 114 .size = sizeof (*amount), 115 .num_params = 1, 116 }; 117 118 return res; 119 } 120 121 122 /** 123 * Function called to convert input amount into SQL parameter as tuple. 124 * 125 * @param cls closure 126 * @param data pointer to input argument, here a `struct TALER_Amount` 127 * @param data_len number of bytes in @a data (if applicable) 128 * @param[out] param_values SQL data to set 129 * @param[out] param_lengths SQL length data to set 130 * @param[out] param_formats SQL format data to set 131 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 132 * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc() 133 * @param scratch_length number of entries left in @a scratch 134 * @return -1 on error, number of offsets used in @a scratch otherwise 135 */ 136 static int 137 qconv_amount_tuple (void *cls, 138 const void *data, 139 size_t data_len, 140 void *param_values[], 141 int param_lengths[], 142 int param_formats[], 143 unsigned int param_length, 144 void *scratch[], 145 unsigned int scratch_length) 146 { 147 struct GNUNET_PQ_Context *db = cls; 148 const struct TALER_Amount *amount = data; 149 size_t sz; 150 151 GNUNET_assert (NULL != db); 152 GNUNET_assert (NULL != amount); 153 GNUNET_assert (1 == param_length); 154 GNUNET_assert (1 <= scratch_length); 155 GNUNET_assert (sizeof (struct TALER_Amount) == data_len); 156 GNUNET_static_assert (sizeof(uint32_t) == sizeof(Oid)); 157 { 158 char *out; 159 Oid oid_v; 160 Oid oid_f; 161 162 GNUNET_assert (GNUNET_OK == 163 GNUNET_PQ_get_oid_by_name (db, 164 "int8", 165 &oid_v)); 166 GNUNET_assert (GNUNET_OK == 167 GNUNET_PQ_get_oid_by_name (db, 168 "int4", 169 &oid_f)); 170 171 { 172 struct TALER_PQ_AmountP d 173 = TALER_PQ_make_taler_pq_amount_ (amount, 174 oid_v, 175 oid_f); 176 177 sz = sizeof(d); 178 out = GNUNET_malloc (sz); 179 scratch[0] = out; 180 GNUNET_memcpy (out, 181 &d, 182 sizeof(d)); 183 } 184 } 185 186 param_values[0] = scratch[0]; 187 param_lengths[0] = sz; 188 param_formats[0] = 1; 189 190 return 1; 191 } 192 193 194 struct GNUNET_PQ_QueryParam 195 TALER_PQ_query_param_amount ( 196 const struct GNUNET_PQ_Context *db, 197 const struct TALER_Amount *amount) 198 { 199 struct GNUNET_PQ_QueryParam res = { 200 .conv_cls = (void *) db, 201 .conv = &qconv_amount_tuple, 202 .data = amount, 203 .size = sizeof (*amount), 204 .num_params = 1, 205 }; 206 207 return res; 208 } 209 210 211 /** 212 * Function called to convert input argument into SQL parameters. 213 * 214 * @param cls closure 215 * @param data pointer to input argument 216 * @param data_len number of bytes in @a data (if applicable) 217 * @param[out] param_values SQL data to set 218 * @param[out] param_lengths SQL length data to set 219 * @param[out] param_formats SQL format data to set 220 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 221 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 222 * @param scratch_length number of entries left in @a scratch 223 * @return -1 on error, number of offsets used in @a scratch otherwise 224 */ 225 static int 226 qconv_denom_pub (void *cls, 227 const void *data, 228 size_t data_len, 229 void *param_values[], 230 int param_lengths[], 231 int param_formats[], 232 unsigned int param_length, 233 void *scratch[], 234 unsigned int scratch_length) 235 { 236 const struct TALER_DenominationPublicKey *denom_pub = data; 237 const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp = denom_pub->bsign_pub_key; 238 size_t tlen; 239 size_t len; 240 uint32_t be[2]; 241 char *buf; 242 void *tbuf; 243 244 (void) cls; 245 (void) data_len; 246 GNUNET_assert (1 == param_length); 247 GNUNET_assert (scratch_length > 0); 248 GNUNET_break (NULL == cls); 249 be[0] = htonl ((uint32_t) bsp->cipher); 250 be[1] = htonl (denom_pub->age_mask.bits); 251 switch (bsp->cipher) 252 { 253 case GNUNET_CRYPTO_BSA_RSA: 254 tlen = GNUNET_CRYPTO_rsa_public_key_encode ( 255 bsp->details.rsa_public_key, 256 &tbuf); 257 break; 258 case GNUNET_CRYPTO_BSA_CS: 259 tlen = sizeof (bsp->details.cs_public_key); 260 break; 261 default: 262 GNUNET_assert (0); 263 } 264 len = tlen + sizeof (be); 265 buf = GNUNET_malloc (len); 266 GNUNET_memcpy (buf, 267 be, 268 sizeof (be)); 269 switch (bsp->cipher) 270 { 271 case GNUNET_CRYPTO_BSA_RSA: 272 GNUNET_memcpy (&buf[sizeof (be)], 273 tbuf, 274 tlen); 275 GNUNET_free (tbuf); 276 break; 277 case GNUNET_CRYPTO_BSA_CS: 278 GNUNET_memcpy (&buf[sizeof (be)], 279 &bsp->details.cs_public_key, 280 tlen); 281 break; 282 default: 283 GNUNET_assert (0); 284 } 285 286 scratch[0] = buf; 287 param_values[0] = (void *) buf; 288 param_lengths[0] = len; 289 param_formats[0] = 1; 290 return 1; 291 } 292 293 294 struct GNUNET_PQ_QueryParam 295 TALER_PQ_query_param_denom_pub ( 296 const struct TALER_DenominationPublicKey *denom_pub) 297 { 298 struct GNUNET_PQ_QueryParam res = { 299 .conv = &qconv_denom_pub, 300 .data = denom_pub, 301 .num_params = 1 302 }; 303 304 return res; 305 } 306 307 308 struct GNUNET_PQ_QueryParam 309 TALER_PQ_query_param_denom_sig ( 310 const struct TALER_DenominationSignature *denom_sig) 311 { 312 return GNUNET_PQ_query_param_unblinded_sig (denom_sig->unblinded_sig); 313 } 314 315 316 struct GNUNET_PQ_QueryParam 317 TALER_PQ_query_param_blinded_denom_sig ( 318 const struct TALER_BlindedDenominationSignature *denom_sig) 319 { 320 return GNUNET_PQ_query_param_blinded_sig (denom_sig->blinded_sig); 321 } 322 323 324 /** 325 * Function called to convert input argument into SQL parameters. 326 * 327 * @param cls closure 328 * @param data pointer to input argument 329 * @param data_len number of bytes in @a data (if applicable) 330 * @param[out] param_values SQL data to set 331 * @param[out] param_lengths SQL length data to set 332 * @param[out] param_formats SQL format data to set 333 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 334 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 335 * @param scratch_length number of entries left in @a scratch 336 * @return -1 on error, number of offsets used in @a scratch otherwise 337 */ 338 static int 339 qconv_blinded_planchet (void *cls, 340 const void *data, 341 size_t data_len, 342 void *param_values[], 343 int param_lengths[], 344 int param_formats[], 345 unsigned int param_length, 346 void *scratch[], 347 unsigned int scratch_length) 348 { 349 const struct TALER_BlindedPlanchet *bp = data; 350 const struct GNUNET_CRYPTO_BlindedMessage *bm = bp->blinded_message; 351 size_t tlen; 352 size_t len; 353 uint32_t be[2]; 354 char *buf; 355 356 (void) cls; 357 (void) data_len; 358 GNUNET_assert (1 == param_length); 359 GNUNET_assert (scratch_length > 0); 360 GNUNET_break (NULL == cls); 361 be[0] = htonl ((uint32_t) bm->cipher); 362 be[1] = htonl (0x0100); /* magic marker: blinded */ 363 switch (bm->cipher) 364 { 365 case GNUNET_CRYPTO_BSA_RSA: 366 tlen = bm->details.rsa_blinded_message.blinded_msg_size; 367 break; 368 case GNUNET_CRYPTO_BSA_CS: 369 tlen = sizeof (bm->details.cs_blinded_message); 370 break; 371 default: 372 GNUNET_assert (0); 373 } 374 len = tlen + sizeof (be); 375 buf = GNUNET_malloc (len); 376 GNUNET_memcpy (buf, 377 &be, 378 sizeof (be)); 379 switch (bm->cipher) 380 { 381 case GNUNET_CRYPTO_BSA_RSA: 382 GNUNET_memcpy (&buf[sizeof (be)], 383 bm->details.rsa_blinded_message.blinded_msg, 384 tlen); 385 break; 386 case GNUNET_CRYPTO_BSA_CS: 387 GNUNET_memcpy (&buf[sizeof (be)], 388 &bm->details.cs_blinded_message, 389 tlen); 390 break; 391 default: 392 GNUNET_assert (0); 393 } 394 scratch[0] = buf; 395 param_values[0] = (void *) buf; 396 param_lengths[0] = len; 397 param_formats[0] = 1; 398 return 1; 399 } 400 401 402 struct GNUNET_PQ_QueryParam 403 TALER_PQ_query_param_blinded_planchet ( 404 const struct TALER_BlindedPlanchet *bp) 405 { 406 struct GNUNET_PQ_QueryParam res = { 407 .conv = &qconv_blinded_planchet, 408 .data = bp, 409 .num_params = 1 410 }; 411 412 return res; 413 } 414 415 416 /** 417 * Function called to convert input argument into SQL parameters. 418 * 419 * @param cls closure 420 * @param data pointer to input argument 421 * @param data_len number of bytes in @a data (if applicable) 422 * @param[out] param_values SQL data to set 423 * @param[out] param_lengths SQL length data to set 424 * @param[out] param_formats SQL format data to set 425 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 426 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 427 * @param scratch_length number of entries left in @a scratch 428 * @return -1 on error, number of offsets used in @a scratch otherwise 429 */ 430 static int 431 qconv_exchange_blinding_values (void *cls, 432 const void *data, 433 size_t data_len, 434 void *param_values[], 435 int param_lengths[], 436 int param_formats[], 437 unsigned int param_length, 438 void *scratch[], 439 unsigned int scratch_length) 440 { 441 const struct TALER_ExchangeBlindingValues *blinding_values = data; 442 const struct GNUNET_CRYPTO_BlindingInputValues *bi = 443 blinding_values->blinding_inputs; 444 size_t tlen; 445 size_t len; 446 uint32_t be[2]; 447 char *buf; 448 449 (void) cls; 450 (void) data_len; 451 GNUNET_assert (1 == param_length); 452 GNUNET_assert (scratch_length > 0); 453 GNUNET_break (NULL == cls); 454 be[0] = htonl ((uint32_t) bi->cipher); 455 be[1] = htonl (0x010000); /* magic marker: EWV */ 456 switch (bi->cipher) 457 { 458 case GNUNET_CRYPTO_BSA_RSA: 459 tlen = 0; 460 break; 461 case GNUNET_CRYPTO_BSA_CS: 462 tlen = sizeof (struct GNUNET_CRYPTO_CSPublicRPairP); 463 break; 464 default: 465 GNUNET_assert (0); 466 } 467 len = tlen + sizeof (be); 468 buf = GNUNET_malloc (len); 469 GNUNET_memcpy (buf, 470 &be, 471 sizeof (be)); 472 switch (bi->cipher) 473 { 474 case GNUNET_CRYPTO_BSA_RSA: 475 break; 476 case GNUNET_CRYPTO_BSA_CS: 477 GNUNET_memcpy (&buf[sizeof (be)], 478 &bi->details.cs_values, 479 tlen); 480 break; 481 default: 482 GNUNET_assert (0); 483 } 484 scratch[0] = buf; 485 param_values[0] = (void *) buf; 486 param_lengths[0] = len; 487 param_formats[0] = 1; 488 return 1; 489 } 490 491 492 struct GNUNET_PQ_QueryParam 493 TALER_PQ_query_param_exchange_blinding_values ( 494 const struct TALER_ExchangeBlindingValues *blinding_values) 495 { 496 struct GNUNET_PQ_QueryParam res = { 497 .conv = &qconv_exchange_blinding_values, 498 .data = blinding_values, 499 .num_params = 1 500 }; 501 502 return res; 503 } 504 505 506 /** 507 * Function called to convert input argument into SQL parameters. 508 * 509 * @param cls closure 510 * @param data pointer to input argument, here a `json_t *` 511 * @param data_len number of bytes in @a data (if applicable) 512 * @param[out] param_values SQL data to set 513 * @param[out] param_lengths SQL length data to set 514 * @param[out] param_formats SQL format data to set 515 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 516 * @param[out] scratch buffer for dynamic allocations (to be done via GNUNET_malloc() 517 * @param scratch_length number of entries left in @a scratch 518 * @return -1 on error, number of offsets used in @a scratch otherwise 519 */ 520 static int 521 qconv_json (void *cls, 522 const void *data, 523 size_t data_len, 524 void *param_values[], 525 int param_lengths[], 526 int param_formats[], 527 unsigned int param_length, 528 void *scratch[], 529 unsigned int scratch_length) 530 { 531 const json_t *json = data; 532 char *str; 533 534 (void) cls; 535 (void) data_len; 536 GNUNET_assert (1 == param_length); 537 GNUNET_assert (scratch_length > 0); 538 str = json_dumps (json, 539 JSON_COMPACT); 540 if (NULL == str) 541 { 542 GNUNET_break (0); 543 return -1; 544 } 545 scratch[0] = str; 546 param_values[0] = (void *) str; 547 param_lengths[0] = strlen (str); 548 param_formats[0] = 1; 549 return 1; 550 } 551 552 553 struct GNUNET_PQ_QueryParam 554 TALER_PQ_query_param_json (const json_t *x) 555 { 556 struct GNUNET_PQ_QueryParam res = { 557 .conv = &qconv_json, 558 .data = x, 559 .num_params = 1 560 }; 561 562 return res; 563 } 564 565 566 /** ------------------- Array support -----------------------------------**/ 567 568 /** 569 * Closure for the array type handlers. 570 * 571 * May contain sizes information for the data, given (and handled) by the 572 * caller. 573 */ 574 struct qconv_array_cls 575 { 576 /** 577 * If not null, contains the array of sizes (the size of the array is the 578 * .size field in the ambient GNUNET_PQ_QueryParam struct). We do not free 579 * this memory. 580 * 581 * If not null, this value has precedence over @a sizes, which MUST be NULL */ 582 const size_t *sizes; 583 584 /** 585 * If @a size and @a c_sizes are NULL, this field defines the same size 586 * for each element in the array. 587 */ 588 size_t same_size; 589 590 /** 591 * If true, the array parameter to the data pointer to the qconv_array is a 592 * continuous byte array of data, either with @a same_size each or sizes 593 * provided bytes by @a sizes; 594 */ 595 bool continuous; 596 597 /** 598 * Type of the array elements 599 */ 600 enum TALER_PQ_ArrayType typ; 601 602 /** 603 * Oid of the array elements 604 */ 605 Oid oid; 606 607 /** 608 * db context, needed for OID-lookup of basis-types 609 */ 610 struct GNUNET_PQ_Context *db; 611 }; 612 613 /** 614 * Callback to cleanup a qconv_array_cls to be used during 615 * GNUNET_PQ_cleanup_query_params_closures 616 */ 617 static void 618 qconv_array_cls_cleanup (void *cls) 619 { 620 GNUNET_free (cls); 621 } 622 623 624 /** 625 * Function called to convert input argument into SQL parameters for arrays 626 * 627 * Note: the format for the encoding of arrays for libpq is not very well 628 * documented. We peeked into various sources (postgresql and libpqtypes) for 629 * guidance. 630 * 631 * @param cls Closure of type struct qconv_array_cls* 632 * @param data Pointer to first element in the array 633 * @param data_len Number of _elements_ in array @a data (if applicable) 634 * @param[out] param_values SQL data to set 635 * @param[out] param_lengths SQL length data to set 636 * @param[out] param_formats SQL format data to set 637 * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays 638 * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() 639 * @param scratch_length number of entries left in @a scratch 640 * @return -1 on error, number of offsets used in @a scratch otherwise 641 */ 642 static int 643 qconv_array ( 644 void *cls, 645 const void *data, 646 size_t data_len, 647 void *param_values[], 648 int param_lengths[], 649 int param_formats[], 650 unsigned int param_length, 651 void *scratch[], 652 unsigned int scratch_length) 653 { 654 struct qconv_array_cls *meta = cls; 655 size_t num = data_len; 656 size_t total_size; 657 const size_t *sizes; 658 bool same_sized; 659 void *elements = NULL; 660 bool noerror = true; 661 /* needed to capture the encoded rsa signatures */ 662 void **buffers = NULL; 663 size_t *buffer_lengths = NULL; 664 665 (void) (param_length); 666 (void) (scratch_length); 667 668 GNUNET_assert (NULL != meta); 669 GNUNET_assert (num < INT_MAX); 670 671 sizes = meta->sizes; 672 same_sized = (0 != meta->same_size); 673 674 #define RETURN_UNLESS(cond) \ 675 do { \ 676 if (! (cond)) \ 677 { \ 678 GNUNET_break ((cond)); \ 679 noerror = false; \ 680 goto DONE; \ 681 } \ 682 } while (0) 683 684 /* Calculate sizes and check bounds */ 685 { 686 /* num * length-field */ 687 size_t x = sizeof(uint32_t); 688 size_t y = x * num; 689 RETURN_UNLESS ((0 == num) || (y / num == x)); 690 691 /* size of header */ 692 total_size = x = sizeof(struct GNUNET_PQ_ArrayHeader_P); 693 total_size += y; 694 RETURN_UNLESS (total_size >= x); 695 696 /* sizes of elements */ 697 if (same_sized) 698 { 699 x = num * meta->same_size; 700 RETURN_UNLESS ((0 == num) || (x / num == meta->same_size)); 701 702 y = total_size; 703 total_size += x; 704 RETURN_UNLESS (total_size >= y); 705 } 706 else /* sizes are different per element */ 707 { 708 switch (meta->typ) 709 { 710 case TALER_PQ_array_of_amount_currency: 711 { 712 const struct TALER_Amount *amounts = data; 713 Oid oid_v; 714 Oid oid_f; 715 Oid oid_c; 716 717 buffer_lengths = GNUNET_new_array (num, size_t); 718 /* hoist out of loop? */ 719 GNUNET_assert (GNUNET_OK == 720 GNUNET_PQ_get_oid_by_name (meta->db, 721 "int8", 722 &oid_v)); 723 GNUNET_assert (GNUNET_OK == 724 GNUNET_PQ_get_oid_by_name (meta->db, 725 "int4", 726 &oid_f)); 727 GNUNET_assert (GNUNET_OK == 728 GNUNET_PQ_get_oid_by_name (meta->db, 729 "varchar", 730 &oid_c)); 731 for (size_t i = 0; i<num; i++) 732 { 733 struct TALER_PQ_AmountCurrencyP am; 734 size_t len; 735 736 len = TALER_PQ_make_taler_pq_amount_currency_ ( 737 &amounts[i], 738 oid_v, 739 oid_f, 740 oid_c, 741 &am); 742 buffer_lengths[i] = len; 743 y = total_size; 744 total_size += len; 745 RETURN_UNLESS (total_size >= y); 746 } 747 sizes = buffer_lengths; 748 break; 749 } 750 case TALER_PQ_array_of_blinded_denom_sig: 751 { 752 const struct TALER_BlindedDenominationSignature *denom_sigs = data; 753 size_t len; 754 755 buffers = GNUNET_new_array (num, void *); 756 buffer_lengths = GNUNET_new_array (num, size_t); 757 758 for (size_t i = 0; i<num; i++) 759 { 760 const struct GNUNET_CRYPTO_BlindedSignature *bs = 761 denom_sigs[i].blinded_sig; 762 763 switch (bs->cipher) 764 { 765 case GNUNET_CRYPTO_BSA_RSA: 766 len = GNUNET_CRYPTO_rsa_signature_encode ( 767 bs->details.blinded_rsa_signature, 768 &buffers[i]); 769 RETURN_UNLESS (len != 0); 770 break; 771 case GNUNET_CRYPTO_BSA_CS: 772 len = sizeof (bs->details.blinded_cs_answer); 773 break; 774 default: 775 GNUNET_assert (0); 776 } 777 778 /* for the cipher and marker */ 779 len += 2 * sizeof(uint32_t); 780 buffer_lengths[i] = len; 781 782 y = total_size; 783 total_size += len; 784 RETURN_UNLESS (total_size >= y); 785 } 786 sizes = buffer_lengths; 787 break; 788 } 789 default: 790 GNUNET_assert (0); 791 } 792 } 793 794 RETURN_UNLESS (INT_MAX > total_size); 795 RETURN_UNLESS (0 != total_size); 796 797 elements = GNUNET_malloc (total_size); 798 } 799 800 /* Write data */ 801 { 802 char *out = elements; 803 struct GNUNET_PQ_ArrayHeader_P h = { 804 .ndim = htonl (1), /* We only support one-dimensional arrays */ 805 .has_null = htonl (0), /* We do not support NULL entries in arrays */ 806 .lbound = htonl (1), /* Default start index value */ 807 .dim = htonl (num), 808 .oid = htonl (meta->oid), 809 }; 810 811 /* Write header */ 812 GNUNET_memcpy (out, 813 &h, 814 sizeof(h)); 815 out += sizeof(h); 816 817 /* Write elements */ 818 for (size_t i = 0; i < num; i++) 819 { 820 size_t sz = same_sized ? meta->same_size : sizes[i]; 821 822 *(uint32_t *) out = htonl (sz); 823 out += sizeof(uint32_t); 824 switch (meta->typ) 825 { 826 case TALER_PQ_array_of_amount: 827 { 828 const struct TALER_Amount *amounts = data; 829 Oid oid_v; 830 Oid oid_f; 831 832 /* hoist out of loop? */ 833 GNUNET_assert (GNUNET_OK == 834 GNUNET_PQ_get_oid_by_name (meta->db, 835 "int8", 836 &oid_v)); 837 GNUNET_assert (GNUNET_OK == 838 GNUNET_PQ_get_oid_by_name (meta->db, 839 "int4", 840 &oid_f)); 841 { 842 struct TALER_PQ_AmountP am 843 = TALER_PQ_make_taler_pq_amount_ ( 844 &amounts[i], 845 oid_v, 846 oid_f); 847 848 GNUNET_memcpy (out, 849 &am, 850 sizeof(am)); 851 } 852 break; 853 } 854 case TALER_PQ_array_of_amount_currency: 855 { 856 const struct TALER_Amount *amounts = data; 857 Oid oid_v; 858 Oid oid_f; 859 Oid oid_c; 860 861 /* hoist out of loop? */ 862 GNUNET_assert (GNUNET_OK == 863 GNUNET_PQ_get_oid_by_name (meta->db, 864 "int8", 865 &oid_v)); 866 GNUNET_assert (GNUNET_OK == 867 GNUNET_PQ_get_oid_by_name (meta->db, 868 "int4", 869 &oid_f)); 870 GNUNET_assert (GNUNET_OK == 871 GNUNET_PQ_get_oid_by_name (meta->db, 872 "varchar", 873 &oid_c)); 874 { 875 struct TALER_PQ_AmountCurrencyP am; 876 size_t len; 877 878 len = TALER_PQ_make_taler_pq_amount_currency_ ( 879 &amounts[i], 880 oid_v, 881 oid_f, 882 oid_c, 883 &am); 884 GNUNET_memcpy (out, 885 &am, 886 len); 887 } 888 break; 889 } 890 case TALER_PQ_array_of_blinded_denom_sig: 891 { 892 const struct TALER_BlindedDenominationSignature *denom_sigs = data; 893 const struct GNUNET_CRYPTO_BlindedSignature *bs = 894 denom_sigs[i].blinded_sig; 895 uint32_t be[2]; 896 897 be[0] = htonl ((uint32_t) bs->cipher); 898 be[1] = htonl (0x01); /* magic margker: blinded */ 899 GNUNET_memcpy (out, 900 &be, 901 sizeof(be)); 902 out += sizeof(be); 903 sz -= sizeof(be); 904 905 switch (bs->cipher) 906 { 907 case GNUNET_CRYPTO_BSA_RSA: 908 /* For RSA, 'same_sized' must have been false */ 909 GNUNET_assert (NULL != buffers); 910 GNUNET_memcpy (out, 911 buffers[i], 912 sz); 913 break; 914 case GNUNET_CRYPTO_BSA_CS: 915 GNUNET_memcpy (out, 916 &bs->details.blinded_cs_answer, 917 sz); 918 break; 919 default: 920 GNUNET_assert (0); 921 } 922 break; 923 } 924 case TALER_PQ_array_of_blinded_coin_hash: 925 { 926 const struct TALER_BlindedCoinHashP *coin_hs = data; 927 928 GNUNET_memcpy (out, 929 &coin_hs[i], 930 sizeof(struct TALER_BlindedCoinHashP)); 931 932 break; 933 } 934 case TALER_PQ_array_of_denom_hash: 935 { 936 const struct TALER_DenominationHashP *denom_hs = data; 937 938 GNUNET_memcpy (out, 939 &denom_hs[i], 940 sizeof(struct TALER_DenominationHashP)); 941 break; 942 } 943 case TALER_PQ_array_of_hash_code: 944 { 945 const struct GNUNET_HashCode *hashes = data; 946 947 GNUNET_memcpy (out, 948 &hashes[i], 949 sizeof(struct GNUNET_HashCode)); 950 break; 951 } 952 case TALER_PQ_array_of_cs_r_pub: 953 { 954 const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs = data; 955 956 GNUNET_memcpy (out, 957 &cs_r_pubs[i], 958 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP)); 959 break; 960 } 961 default: 962 { 963 GNUNET_assert (0); 964 break; 965 } 966 } 967 out += sz; 968 } 969 } 970 param_values[0] = elements; 971 param_lengths[0] = total_size; 972 param_formats[0] = 1; 973 scratch[0] = elements; 974 975 DONE: 976 if (NULL != buffers) 977 { 978 for (size_t i = 0; i<num; i++) 979 GNUNET_free (buffers[i]); 980 GNUNET_free (buffers); 981 } 982 GNUNET_free (buffer_lengths); 983 if (noerror) 984 return 1; 985 return -1; 986 } 987 988 989 /** 990 * Function to generate a typ specific query parameter and corresponding closure 991 * 992 * @param num Number of elements in @a elements 993 * @param continuous If true, @a elements is an continuous array of data 994 * @param elements Array of @a num elements, either continuous or pointers 995 * @param sizes Array of @a num sizes, one per element, may be NULL 996 * @param same_size If not 0, all elements in @a elements have this size 997 * @param typ Supported internal type of each element in @a elements 998 * @param oid Oid of the type to be used in Postgres 999 * @param[in,out] db our database handle for looking up OIDs 1000 * @return Query parameter 1001 */ 1002 static struct GNUNET_PQ_QueryParam 1003 query_param_array_generic ( 1004 unsigned int num, 1005 bool continuous, 1006 const void *elements, 1007 const size_t *sizes, 1008 size_t same_size, 1009 enum TALER_PQ_ArrayType typ, 1010 Oid oid, 1011 struct GNUNET_PQ_Context *db) 1012 { 1013 struct qconv_array_cls *meta = GNUNET_new (struct qconv_array_cls); 1014 1015 meta->typ = typ; 1016 meta->oid = oid; 1017 meta->sizes = sizes; 1018 meta->same_size = same_size; 1019 meta->continuous = continuous; 1020 meta->db = db; 1021 1022 { 1023 struct GNUNET_PQ_QueryParam res = { 1024 .conv = qconv_array, 1025 .conv_cls = meta, 1026 .conv_cls_cleanup = qconv_array_cls_cleanup, 1027 .data = elements, 1028 .size = num, 1029 .num_params = 1, 1030 }; 1031 1032 return res; 1033 } 1034 } 1035 1036 1037 struct GNUNET_PQ_QueryParam 1038 TALER_PQ_query_param_array_blinded_denom_sig ( 1039 size_t num, 1040 const struct TALER_BlindedDenominationSignature *denom_sigs, 1041 struct GNUNET_PQ_Context *db) 1042 { 1043 Oid oid; 1044 1045 GNUNET_assert (GNUNET_OK == 1046 GNUNET_PQ_get_oid_by_name (db, 1047 "bytea", 1048 &oid)); 1049 return query_param_array_generic (num, 1050 true, 1051 denom_sigs, 1052 NULL, 1053 0, 1054 TALER_PQ_array_of_blinded_denom_sig, 1055 oid, 1056 NULL); 1057 } 1058 1059 1060 struct GNUNET_PQ_QueryParam 1061 TALER_PQ_query_param_array_blinded_coin_hash ( 1062 size_t num, 1063 const struct TALER_BlindedCoinHashP *coin_hs, 1064 struct GNUNET_PQ_Context *db) 1065 { 1066 Oid oid; 1067 1068 GNUNET_assert (GNUNET_OK == 1069 GNUNET_PQ_get_oid_by_name (db, 1070 "bytea", 1071 &oid)); 1072 return query_param_array_generic (num, 1073 true, 1074 coin_hs, 1075 NULL, 1076 sizeof(struct TALER_BlindedCoinHashP), 1077 TALER_PQ_array_of_blinded_coin_hash, 1078 oid, 1079 NULL); 1080 } 1081 1082 1083 struct GNUNET_PQ_QueryParam 1084 TALER_PQ_query_param_array_denom_hash ( 1085 size_t num, 1086 const struct TALER_DenominationHashP *denom_hs, 1087 struct GNUNET_PQ_Context *db) 1088 { 1089 Oid oid; 1090 1091 GNUNET_assert (GNUNET_OK == 1092 GNUNET_PQ_get_oid_by_name (db, 1093 "bytea", 1094 &oid)); 1095 return query_param_array_generic (num, 1096 true, 1097 denom_hs, 1098 NULL, 1099 sizeof(struct TALER_DenominationHashP), 1100 TALER_PQ_array_of_denom_hash, 1101 oid, 1102 NULL); 1103 } 1104 1105 1106 struct GNUNET_PQ_QueryParam 1107 TALER_PQ_query_param_array_hash_code ( 1108 size_t num, 1109 const struct GNUNET_HashCode *hashes, 1110 struct GNUNET_PQ_Context *db) 1111 { 1112 Oid oid; 1113 GNUNET_assert (GNUNET_OK == 1114 GNUNET_PQ_get_oid_by_name (db, "gnunet_hashcode", &oid)); 1115 return query_param_array_generic (num, 1116 true, 1117 hashes, 1118 NULL, 1119 sizeof(struct GNUNET_HashCode), 1120 TALER_PQ_array_of_hash_code, 1121 oid, 1122 NULL); 1123 } 1124 1125 1126 struct GNUNET_PQ_QueryParam 1127 TALER_PQ_query_param_array_amount ( 1128 size_t num, 1129 const struct TALER_Amount *amounts, 1130 struct GNUNET_PQ_Context *db) 1131 { 1132 Oid oid; 1133 1134 GNUNET_assert (GNUNET_OK == 1135 GNUNET_PQ_get_oid_by_name (db, 1136 "taler_amount", 1137 &oid)); 1138 return query_param_array_generic ( 1139 num, 1140 true, 1141 amounts, 1142 NULL, 1143 sizeof(struct TALER_PQ_AmountP), 1144 TALER_PQ_array_of_amount, 1145 oid, 1146 db); 1147 } 1148 1149 1150 struct GNUNET_PQ_QueryParam 1151 TALER_PQ_query_param_array_amount_with_currency ( 1152 size_t num, 1153 const struct TALER_Amount *amounts, 1154 struct GNUNET_PQ_Context *db) 1155 { 1156 Oid oid; 1157 1158 GNUNET_assert (GNUNET_OK == 1159 GNUNET_PQ_get_oid_by_name (db, 1160 "taler_amount_currency", 1161 &oid)); 1162 return query_param_array_generic ( 1163 num, 1164 true, 1165 amounts, 1166 NULL, 1167 0, /* currency is technically variable length */ 1168 TALER_PQ_array_of_amount_currency, 1169 oid, 1170 db); 1171 } 1172 1173 1174 struct GNUNET_PQ_QueryParam 1175 TALER_PQ_query_param_array_cs_r_pub ( 1176 size_t num, 1177 const struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_pubs, 1178 struct GNUNET_PQ_Context *db) 1179 { 1180 Oid oid; 1181 1182 GNUNET_assert (GNUNET_OK == 1183 GNUNET_PQ_get_oid_by_name (db, 1184 "bytea", 1185 &oid)); 1186 return query_param_array_generic ( 1187 num, 1188 true, 1189 cs_r_pubs, 1190 NULL, 1191 sizeof(struct GNUNET_CRYPTO_CSPublicRPairP), 1192 TALER_PQ_array_of_cs_r_pub, 1193 oid, 1194 db); 1195 } 1196 1197 1198 /* end of pq/pq_query_helper.c */