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