age_restriction.c (21725B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-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 util/age_restriction.c 18 * @brief Functions that are used for age restriction 19 * @author Özgür Kesim 20 */ 21 #include "platform.h" /* UNNECESSARY? */ 22 #include "taler/taler_util.h" 23 #include "taler/taler_signatures.h" 24 #include <gnunet/gnunet_json_lib.h> 25 #include <gcrypt.h> 26 #include <stdint.h> 27 28 struct 29 #ifndef AGE_RESTRICTION_WITH_ECDSA 30 GNUNET_CRYPTO_Edx25519PublicKey 31 #else 32 GNUNET_CRYPTO_EcdsaPublicKey 33 #endif 34 TALER_age_commitment_base_public_key = { 35 .q_y = { 0x64, 0x41, 0xb9, 0xbd, 0xbf, 0x14, 0x39, 0x8e, 36 0x46, 0xeb, 0x5c, 0x1d, 0x34, 0xd3, 0x9b, 0x2f, 37 0x9b, 0x7d, 0xc8, 0x18, 0xeb, 0x9c, 0x09, 0xfb, 38 0x43, 0xad, 0x16, 0x64, 0xbc, 0x18, 0x49, 0xb5}, 39 }; 40 41 void 42 TALER_age_commitment_hash ( 43 const struct TALER_AgeCommitment *commitment, 44 struct TALER_AgeCommitmentHashP *ahash) 45 { 46 struct GNUNET_HashContext *hash_context; 47 struct GNUNET_HashCode hash; 48 49 GNUNET_assert (NULL != ahash); 50 if (NULL == commitment) 51 { 52 memset (ahash, 0, sizeof(struct TALER_AgeCommitmentHashP)); 53 return; 54 } 55 56 GNUNET_assert (__builtin_popcount (commitment->mask.bits) - 1 == 57 (int) commitment->num); 58 59 hash_context = GNUNET_CRYPTO_hash_context_start (); 60 61 for (size_t i = 0; i < commitment->num; i++) 62 { 63 GNUNET_CRYPTO_hash_context_read (hash_context, 64 &commitment->pubs[i], 65 sizeof(commitment->pubs[i])); 66 } 67 68 GNUNET_CRYPTO_hash_context_finish (hash_context, 69 &hash); 70 GNUNET_memcpy (&ahash->shash.bits, 71 &hash.bits, 72 sizeof(ahash->shash.bits)); 73 } 74 75 76 /* To a given age value between 0 and 31, returns the index of the age group 77 * defined by the given mask. 78 */ 79 uint8_t 80 TALER_get_age_group ( 81 const struct TALER_AgeMask *mask, 82 uint8_t age) 83 { 84 uint32_t m = mask->bits; 85 uint8_t i = 0; 86 87 while (m > 0) 88 { 89 if (0 >= age) 90 break; 91 m = m >> 1; 92 i += m & 1; 93 age--; 94 } 95 return i; 96 } 97 98 99 uint8_t 100 TALER_get_lowest_age ( 101 const struct TALER_AgeMask *mask, 102 uint8_t age) 103 { 104 uint32_t m = mask->bits; 105 uint8_t group = TALER_get_age_group (mask, age); 106 uint8_t lowest = 0; 107 108 while (group > 0) 109 { 110 m = m >> 1; 111 if (m & 1) 112 group--; 113 lowest++; 114 } 115 116 return lowest; 117 } 118 119 120 #ifdef AGE_RESTRICTION_WITH_ECDSA 121 /** 122 * @brief Helper function to generate a ECDSA private key 123 * 124 * @param seed Input seed 125 * @param size Size of the seed in bytes 126 * @param[out] pkey ECDSA private key 127 */ 128 static void 129 ecdsa_create_from_seed ( 130 const void *seed, 131 size_t seed_size, 132 struct GNUNET_CRYPTO_EcdsaPrivateKey *key) 133 { 134 enum GNUNET_GenericReturnValue ret; 135 136 GNUNET_assert ( 137 GNUNET_OK == 138 GNUNET_CRYPTO_hkdf_gnunet (key, 139 sizeof (*key), 140 &seed, 141 seed_size, 142 "age commitment", 143 sizeof ("age commitment") - 1)); 144 /* See GNUNET_CRYPTO_ecdsa_key_create */ 145 key->d[0] &= 248; 146 key->d[31] &= 127; 147 key->d[31] |= 64; 148 } 149 150 151 #endif 152 153 154 void 155 TALER_age_restriction_commit ( 156 const struct TALER_AgeMask *mask, 157 uint8_t age, 158 const struct GNUNET_HashCode *seed, 159 struct TALER_AgeCommitmentProof *ncp) 160 { 161 struct GNUNET_HashCode seed_i; 162 uint8_t num_pub; 163 uint8_t num_priv; 164 size_t i; 165 166 GNUNET_assert (NULL != mask); 167 GNUNET_assert (NULL != seed); 168 GNUNET_assert (NULL != ncp); 169 GNUNET_assert (mask->bits & 1); /* first bit must have been set */ 170 171 num_pub = __builtin_popcount (mask->bits) - 1; 172 num_priv = TALER_get_age_group (mask, age); 173 174 GNUNET_assert (31 > num_priv); 175 GNUNET_assert (num_priv <= num_pub); 176 177 seed_i = *seed; 178 ncp->commitment.mask.bits = mask->bits; 179 ncp->commitment.num = num_pub; 180 ncp->proof.num = num_priv; 181 ncp->proof.privs = NULL; 182 183 ncp->commitment.pubs = GNUNET_new_array ( 184 num_pub, 185 struct TALER_AgeCommitmentPublicKeyP); 186 187 if (0 < num_priv) 188 ncp->proof.privs = GNUNET_new_array ( 189 num_priv, 190 struct TALER_AgeCommitmentPrivateKeyP); 191 192 /* Create as many private keys as we need and fill the rest of the 193 * public keys with valid curve points. 194 * We need to make sure that the public keys are proper points on the 195 * elliptic curve, so we can't simply fill the struct with random values. */ 196 for (i = 0; i < num_pub; i++) 197 { 198 struct TALER_AgeCommitmentPrivateKeyP key = {0}; 199 struct TALER_AgeCommitmentPrivateKeyP *pkey = &key; 200 201 /* Only save the private keys for age groups less than num_priv */ 202 if (i < num_priv) 203 pkey = &ncp->proof.privs[i]; 204 205 #ifndef AGE_RESTRICTION_WITH_ECDSA 206 GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i, 207 sizeof(seed_i), 208 &pkey->priv); 209 GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, 210 &ncp->commitment.pubs[i].pub); 211 #else 212 ecdsa_create_from_seed (&seed_i, 213 sizeof(seed_i), 214 &pkey->priv); 215 GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv, 216 &ncp->commitment.pubs[i].pub); 217 #endif 218 219 seed_i.bits[0] += 1; 220 } 221 } 222 223 224 enum GNUNET_GenericReturnValue 225 TALER_age_commitment_derive ( 226 const struct TALER_AgeCommitment *orig, 227 const struct GNUNET_HashCode *salt, 228 struct TALER_AgeCommitment *newac) 229 { 230 GNUNET_assert (NULL != newac); 231 GNUNET_assert (((int) orig->num) == 232 __builtin_popcount (orig->mask.bits) - 1); 233 234 newac->mask = orig->mask; 235 newac->num = orig->num; 236 newac->pubs = GNUNET_new_array ( 237 newac->num, 238 struct TALER_AgeCommitmentPublicKeyP); 239 240 #ifndef AGE_RESTRICTION_WITH_ECDSA 241 /* Derive the public keys */ 242 for (size_t i = 0; i < orig->num; i++) 243 { 244 GNUNET_CRYPTO_edx25519_public_key_derive ( 245 &orig->pubs[i].pub, 246 salt, 247 sizeof(*salt), 248 &newac->pubs[i].pub); 249 } 250 #else 251 { 252 const char *label = GNUNET_h2s (salt); 253 254 /* Derive the public keys */ 255 for (size_t i = 0; i < orig->num; i++) 256 { 257 GNUNET_CRYPTO_ecdsa_public_key_derive ( 258 &orig->pubs[i].pub, 259 label, 260 "age commitment derive", 261 &newac->pubs[i].pub); 262 } 263 } 264 #endif 265 266 return GNUNET_OK; 267 } 268 269 270 enum GNUNET_GenericReturnValue 271 TALER_age_commitment_derive_from_secret ( 272 const struct TALER_AgeCommitment *orig, 273 const struct TALER_PlanchetMasterSecretP *secret, 274 struct TALER_AgeCommitment *newac) 275 { 276 struct GNUNET_HashCode salt; 277 enum GNUNET_GenericReturnValue ret; 278 279 ret = GNUNET_CRYPTO_hkdf_gnunet (&salt, 280 sizeof (salt), 281 "age commitment", 282 strlen ("age commitment"), 283 secret, 284 sizeof(*secret)); 285 if (GNUNET_OK != ret) 286 { 287 GNUNET_break (0); 288 return ret; 289 } 290 291 return TALER_age_commitment_derive ( 292 orig, 293 &salt, 294 newac); 295 } 296 297 298 enum GNUNET_GenericReturnValue 299 TALER_age_commitment_proof_derive ( 300 const struct TALER_AgeCommitmentProof *orig, 301 const struct GNUNET_HashCode *salt, 302 struct TALER_AgeCommitmentProof *newacp) 303 { 304 enum GNUNET_GenericReturnValue ret; 305 GNUNET_assert (NULL != newacp); 306 GNUNET_assert (orig->proof.num <= 307 orig->commitment.num); 308 GNUNET_assert (((int) orig->commitment.num) == 309 __builtin_popcount (orig->commitment.mask.bits) - 1); 310 311 ret = TALER_age_commitment_derive ( 312 &orig->commitment, 313 salt, 314 &newacp->commitment); 315 if (GNUNET_OK != ret) 316 { 317 GNUNET_break (0); 318 return ret; 319 } 320 321 newacp->proof.num = orig->proof.num; 322 newacp->proof.privs = NULL; 323 if (0 != newacp->proof.num) 324 newacp->proof.privs = GNUNET_new_array ( 325 newacp->proof.num, 326 struct TALER_AgeCommitmentPrivateKeyP); 327 328 #ifndef AGE_RESTRICTION_WITH_ECDSA 329 /* Derive the private keys */ 330 for (size_t i = 0; i < orig->proof.num; i++) 331 { 332 GNUNET_CRYPTO_edx25519_private_key_derive ( 333 &orig->proof.privs[i].priv, 334 salt, 335 sizeof(*salt), 336 &newacp->proof.privs[i].priv); 337 } 338 #else 339 { 340 const char *label = GNUNET_h2s (salt); 341 342 /* Derive the private keys */ 343 for (size_t i = 0; i < orig->proof.num; i++) 344 { 345 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv; 346 priv = GNUNET_CRYPTO_ecdsa_private_key_derive ( 347 &orig->proof.privs[i].priv, 348 label, 349 "age commitment derive"); 350 newacp->proof.privs[i].priv = *priv; 351 GNUNET_free (priv); 352 } 353 } 354 #endif 355 356 return GNUNET_OK; 357 } 358 359 360 enum GNUNET_GenericReturnValue 361 TALER_age_commitment_proof_derive_from_secret ( 362 const struct TALER_AgeCommitmentProof *orig, 363 const struct TALER_PlanchetMasterSecretP *secret, 364 struct TALER_AgeCommitmentProof *newacp) 365 { 366 struct GNUNET_HashCode salt; 367 enum GNUNET_GenericReturnValue ret; 368 369 ret = GNUNET_CRYPTO_hkdf_gnunet (&salt, 370 sizeof (salt), 371 "age commitment", 372 strlen ("age commitment"), 373 secret, 374 sizeof(*secret)); 375 if (GNUNET_OK != ret) 376 { 377 GNUNET_break (0); 378 return ret; 379 } 380 381 return TALER_age_commitment_proof_derive ( 382 orig, 383 &salt, 384 newacp); 385 } 386 387 388 GNUNET_NETWORK_STRUCT_BEGIN 389 390 /** 391 * Age group mask in network byte order. 392 */ 393 struct TALER_AgeMaskNBO 394 { 395 uint32_t bits_nbo; 396 }; 397 398 /** 399 * Used for attestation of a particular age 400 */ 401 struct TALER_AgeAttestationPPS 402 { 403 /** 404 * Purpose must be #TALER_SIGNATURE_WALLET_AGE_ATTESTATION. 405 * (no GNUNET_PACKED here because the struct is already packed) 406 */ 407 struct GNUNET_CRYPTO_SignaturePurpose purpose; 408 409 /** 410 * Age mask that defines the underlying age groups 411 */ 412 struct TALER_AgeMaskNBO mask GNUNET_PACKED; 413 414 /** 415 * The particular age that this attestation is for. 416 * We use uint32_t here for alignment. 417 */ 418 uint32_t age GNUNET_PACKED; 419 }; 420 421 GNUNET_NETWORK_STRUCT_END 422 423 424 enum GNUNET_GenericReturnValue 425 TALER_age_commitment_attest ( 426 const struct TALER_AgeCommitmentProof *cp, 427 uint8_t age, 428 struct TALER_AgeAttestationP *attest) 429 { 430 uint8_t group; 431 432 GNUNET_assert (NULL != attest); 433 GNUNET_assert (NULL != cp); 434 435 group = TALER_get_age_group (&cp->commitment.mask, 436 age); 437 438 GNUNET_assert (group < 32); 439 440 if (0 == group) 441 { 442 /* Age group 0 means: no attestation necessary. 443 * We set the signature to zero and communicate success. */ 444 memset (attest, 445 0, 446 sizeof(struct TALER_AgeAttestationP)); 447 return GNUNET_OK; 448 } 449 450 if (group > cp->proof.num) 451 return GNUNET_NO; 452 453 { 454 struct TALER_AgeAttestationPPS at = { 455 .purpose.size = htonl (sizeof(at)), 456 .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_AGE_ATTESTATION), 457 .mask.bits_nbo = htonl (cp->commitment.mask.bits), 458 .age = htonl (age), 459 }; 460 461 #ifndef AGE_RESTRICTION_WITH_ECDSA 462 #define sign(a,b,c) GNUNET_CRYPTO_edx25519_sign (a,b,c) 463 #else 464 #define sign(a,b,c) GNUNET_CRYPTO_ecdsa_sign (a,b,c) 465 #endif 466 sign (&cp->proof.privs[group - 1].priv, 467 &at, 468 &attest->signature); 469 } 470 #undef sign 471 472 return GNUNET_OK; 473 } 474 475 476 enum GNUNET_GenericReturnValue 477 TALER_age_commitment_verify ( 478 const struct TALER_AgeCommitment *comm, 479 uint8_t age, 480 const struct TALER_AgeAttestationP *attest) 481 { 482 uint8_t group; 483 484 GNUNET_assert (NULL != attest); 485 GNUNET_assert (NULL != comm); 486 487 group = TALER_get_age_group (&comm->mask, 488 age); 489 490 GNUNET_assert (group < 32); 491 492 /* Age group 0 means: no attestation necessary. */ 493 if (0 == group) 494 return GNUNET_OK; 495 496 if (group > comm->num) 497 { 498 GNUNET_break_op (0); 499 return GNUNET_NO; 500 } 501 502 { 503 struct TALER_AgeAttestationPPS at = { 504 .purpose.size = htonl (sizeof(at)), 505 .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_AGE_ATTESTATION), 506 .mask.bits_nbo = htonl (comm->mask.bits), 507 .age = htonl (age), 508 }; 509 510 #ifndef AGE_RESTRICTION_WITH_ECDSA 511 #define verify(a,b,c,d) GNUNET_CRYPTO_edx25519_verify ((a),(b),(c),(d)) 512 #else 513 #define verify(a,b,c,d) GNUNET_CRYPTO_ecdsa_verify ((a),(b),(c),(d)) 514 #endif 515 return verify (TALER_SIGNATURE_WALLET_AGE_ATTESTATION, 516 &at, 517 &attest->signature, 518 &comm->pubs[group - 1].pub); 519 } 520 #undef verify 521 } 522 523 524 void 525 TALER_age_commitment_free ( 526 struct TALER_AgeCommitment *commitment) 527 { 528 if (NULL == commitment) 529 return; 530 531 if (NULL != commitment->pubs) 532 { 533 GNUNET_free (commitment->pubs); 534 commitment->pubs = NULL; 535 } 536 } 537 538 539 void 540 TALER_age_proof_free ( 541 struct TALER_AgeProof *proof) 542 { 543 if (NULL == proof) 544 return; 545 546 if (NULL != proof->privs) 547 { 548 GNUNET_CRYPTO_zero_keys ( 549 proof->privs, 550 sizeof(*proof->privs) * proof->num); 551 552 GNUNET_free (proof->privs); 553 proof->privs = NULL; 554 } 555 } 556 557 558 void 559 TALER_age_commitment_proof_free ( 560 struct TALER_AgeCommitmentProof *acp) 561 { 562 if (NULL == acp) 563 return; 564 565 if (NULL != acp->proof.privs) 566 { 567 GNUNET_CRYPTO_zero_keys ( 568 acp->proof.privs, 569 sizeof(*acp->proof.privs) * acp->proof.num); 570 571 GNUNET_free (acp->proof.privs); 572 acp->proof.privs = NULL; 573 } 574 575 if (NULL != acp->commitment.pubs) 576 { 577 GNUNET_free (acp->commitment.pubs); 578 acp->commitment.pubs = NULL; 579 } 580 } 581 582 583 struct TALER_AgeCommitmentProof * 584 TALER_age_commitment_proof_duplicate ( 585 const struct TALER_AgeCommitmentProof *acp) 586 { 587 struct TALER_AgeCommitmentProof *nacp; 588 589 GNUNET_assert (NULL != acp); 590 GNUNET_assert (__builtin_popcount (acp->commitment.mask.bits) - 1 == 591 (int) acp->commitment.num); 592 593 nacp = GNUNET_new (struct TALER_AgeCommitmentProof); 594 595 TALER_age_commitment_proof_deep_copy (nacp, acp); 596 return nacp; 597 } 598 599 600 struct TALER_AgeCommitment * 601 TALER_age_commitment_duplicate ( 602 const struct TALER_AgeCommitment *ac) 603 { 604 struct TALER_AgeCommitment *nac; 605 606 GNUNET_assert (NULL != ac); 607 GNUNET_assert (__builtin_popcount (ac->mask.bits) - 1 == 608 (int) ac->num); 609 610 nac = GNUNET_new (struct TALER_AgeCommitment); 611 TALER_age_commitment_deep_copy (nac, ac); 612 return nac; 613 } 614 615 616 void 617 TALER_age_commitment_proof_deep_copy ( 618 struct TALER_AgeCommitmentProof *nacp, 619 const struct TALER_AgeCommitmentProof *acp) 620 { 621 GNUNET_assert (NULL != acp); 622 GNUNET_assert (__builtin_popcount (acp->commitment.mask.bits) - 1 == 623 (int) acp->commitment.num); 624 625 *nacp = *acp; 626 nacp->commitment.pubs = 627 GNUNET_new_array (acp->commitment.num, 628 struct TALER_AgeCommitmentPublicKeyP); 629 nacp->proof.privs = 630 GNUNET_new_array (acp->proof.num, 631 struct TALER_AgeCommitmentPrivateKeyP); 632 633 for (size_t i = 0; i < acp->commitment.num; i++) 634 nacp->commitment.pubs[i] = acp->commitment.pubs[i]; 635 636 for (size_t i = 0; i < acp->proof.num; i++) 637 nacp->proof.privs[i] = acp->proof.privs[i]; 638 } 639 640 641 void 642 TALER_age_commitment_deep_copy ( 643 struct TALER_AgeCommitment *nac, 644 const struct TALER_AgeCommitment *ac) 645 { 646 GNUNET_assert (NULL != ac); 647 GNUNET_assert (__builtin_popcount (ac->mask.bits) - 1 == 648 (int) ac->num); 649 650 *nac = *ac; 651 nac->pubs = 652 GNUNET_new_array (ac->num, 653 struct TALER_AgeCommitmentPublicKeyP); 654 655 for (size_t i = 0; i < ac->num; i++) 656 nac->pubs[i] = ac->pubs[i]; 657 658 } 659 660 661 enum GNUNET_GenericReturnValue 662 TALER_parse_age_group_string ( 663 const char *groups, 664 struct TALER_AgeMask *mask) 665 { 666 667 const char *pos = groups; 668 unsigned int prev = 0; 669 unsigned int val = 0; 670 char c; 671 672 /* reset mask */ 673 mask->bits = 0; 674 675 while (*pos) 676 { 677 c = *pos++; 678 if (':' == c) 679 { 680 if (prev >= val) 681 return GNUNET_SYSERR; 682 683 mask->bits |= 1 << val; 684 prev = val; 685 val = 0; 686 continue; 687 } 688 689 if ('0'>c || '9'<c) 690 return GNUNET_SYSERR; 691 692 val = 10 * val + c - '0'; 693 694 if (0>=val || 32<=val) 695 return GNUNET_SYSERR; 696 } 697 698 if (32<=val || prev>=val) 699 return GNUNET_SYSERR; 700 701 mask->bits |= (1 << val); 702 mask->bits |= 1; // mark zeroth group, too 703 704 return GNUNET_OK; 705 } 706 707 708 const char * 709 TALER_age_mask_to_string ( 710 const struct TALER_AgeMask *mask) 711 { 712 static char buf[256] = {0}; 713 uint32_t bits = mask->bits; 714 unsigned int n = 0; 715 char *pos = buf; 716 717 memset (buf, 0, sizeof(buf)); 718 719 while (bits != 0) 720 { 721 bits >>= 1; 722 n++; 723 if (0 == (bits & 1)) 724 { 725 continue; 726 } 727 728 if (n > 9) 729 { 730 *(pos++) = '0' + n / 10; 731 } 732 *(pos++) = '0' + n % 10; 733 734 if (0 != (bits >> 1)) 735 { 736 *(pos++) = ':'; 737 } 738 } 739 return buf; 740 } 741 742 743 void 744 TALER_age_restriction_from_secret ( 745 const struct TALER_PlanchetMasterSecretP *secret, 746 const struct TALER_AgeMask *mask, 747 const uint8_t max_age, 748 struct TALER_AgeCommitmentProof *ncp) 749 { 750 struct GNUNET_HashCode seed_i = {0}; 751 uint8_t num_pub; 752 uint8_t num_priv; 753 754 GNUNET_assert (NULL != mask); 755 GNUNET_assert (NULL != secret); 756 GNUNET_assert (NULL != ncp); 757 GNUNET_assert (mask->bits & 1); /* fist bit must have been set */ 758 759 num_pub = __builtin_popcount (mask->bits) - 1; 760 num_priv = TALER_get_age_group (mask, max_age); 761 762 GNUNET_assert (31 > num_priv); 763 GNUNET_assert (num_priv <= num_pub); 764 765 ncp->commitment.mask.bits = mask->bits; 766 ncp->commitment.num = num_pub; 767 ncp->proof.num = num_priv; 768 ncp->proof.privs = NULL; 769 ncp->commitment.pubs = GNUNET_new_array ( 770 num_pub, 771 struct TALER_AgeCommitmentPublicKeyP); 772 if (0 < num_priv) 773 ncp->proof.privs = GNUNET_new_array ( 774 num_priv, 775 struct TALER_AgeCommitmentPrivateKeyP); 776 777 /* Create as many private keys as allow with max_age and derive the 778 * corresponding public keys. The rest of the needed public keys are created 779 * by scalar multiplication with the TALER_age_commitment_base_public_key. */ 780 for (size_t i = 0; i < num_pub; i++) 781 { 782 enum GNUNET_GenericReturnValue ret; 783 const char *label = i < num_priv ? "age-commitment" : "age-factor"; 784 785 ret = GNUNET_CRYPTO_hkdf_gnunet (&seed_i, sizeof(seed_i), 786 secret, sizeof(*secret), 787 label, strlen (label), 788 GNUNET_CRYPTO_kdf_arg_auto (&i)); 789 GNUNET_assert (GNUNET_OK == ret); 790 791 /* Only generate and save the private keys and public keys for age groups 792 * less than num_priv */ 793 if (i < num_priv) 794 { 795 struct TALER_AgeCommitmentPrivateKeyP *pkey = &ncp->proof.privs[i]; 796 797 #ifndef AGE_RESTRICTION_WITH_ECDSA 798 GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i, 799 sizeof(seed_i), 800 &pkey->priv); 801 GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, 802 &ncp->commitment.pubs[i].pub); 803 #else 804 ecdsa_create_from_seed (&seed_i, 805 sizeof(seed_i), 806 &pkey->priv); 807 GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv, 808 &ncp->commitment.pubs[i].pub); 809 #endif 810 } 811 else 812 { 813 /* For all indices larger than num_priv, derive a public key from 814 * TALER_age_commitment_base_public_key by scalar multiplication */ 815 #ifndef AGE_RESTRICTION_WITH_ECDSA 816 GNUNET_CRYPTO_edx25519_public_key_derive ( 817 &TALER_age_commitment_base_public_key, 818 &seed_i, 819 sizeof(seed_i), 820 &ncp->commitment.pubs[i].pub); 821 #else 822 823 GNUNET_CRYPTO_ecdsa_public_key_derive ( 824 &TALER_age_commitment_base_public_key, 825 GNUNET_h2s (&seed_i), 826 "age withdraw", 827 &ncp->commitment.pubs[i].pub); 828 #endif 829 } 830 } 831 } 832 833 834 enum GNUNET_GenericReturnValue 835 TALER_parse_coarse_date ( 836 const char *in, 837 const struct TALER_AgeMask *mask, 838 uint32_t *out) 839 { 840 struct tm date = {0}; 841 struct tm limit = {0}; 842 time_t seconds; 843 844 if (NULL == in) 845 { 846 /* FIXME[oec]: correct behaviour? */ 847 *out = 0; 848 return GNUNET_OK; 849 } 850 851 GNUNET_assert (NULL !=mask); 852 GNUNET_assert (NULL !=out); 853 854 if (NULL == strptime (in, "%Y-%m-%d", &date)) 855 { 856 if (NULL == strptime (in, "%Y-%m-00", &date)) 857 if (NULL == strptime (in, "%Y-00-00", &date)) 858 return GNUNET_SYSERR; 859 /* turns out that the day is off by one in the last two cases */ 860 date.tm_mday += 1; 861 } 862 863 seconds = timegm (&date); 864 if (-1 == seconds) 865 return GNUNET_SYSERR; 866 867 /* calculate the limit date for the largest age group */ 868 { 869 time_t l = time (NULL); 870 localtime_r (&l, &limit); 871 } 872 limit.tm_year -= TALER_adult_age (mask); 873 GNUNET_assert (-1 != timegm (&limit)); 874 875 if ((limit.tm_year < date.tm_year) 876 || ((limit.tm_year == date.tm_year) 877 && (limit.tm_mon < date.tm_mon)) 878 || ((limit.tm_year == date.tm_year) 879 && (limit.tm_mon == date.tm_mon) 880 && (limit.tm_mday < date.tm_mday))) 881 *out = seconds / 60 / 60 / 24; 882 else 883 *out = 0; 884 885 return GNUNET_OK; 886 } 887 888 889 /* end util/age_restriction.c */