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