1/* Copyright (c) 2020, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/trust_token.h>
16
17#include <openssl/bn.h>
18#include <openssl/bytestring.h>
19#include <openssl/ec.h>
20#include <openssl/err.h>
21#include <openssl/mem.h>
22#include <openssl/nid.h>
23#include <openssl/rand.h>
24#include <openssl/sha.h>
25
26#include "../ec_extra/internal.h"
27#include "../fipsmodule/ec/internal.h"
28
29#include "internal.h"
30
31
32typedef int (*hash_to_group_func_t)(const EC_GROUP *group, EC_RAW_POINT *out,
33 const uint8_t t[TRUST_TOKEN_NONCE_SIZE]);
34typedef int (*hash_to_scalar_func_t)(const EC_GROUP *group, EC_SCALAR *out,
35 uint8_t *buf, size_t len);
36
37typedef struct {
38 const EC_GROUP *group;
39
40 // hash_to_group implements the HashToGroup operation for VOPRFs. It returns
41 // one on success and zero on error.
42 hash_to_group_func_t hash_to_group;
43 // hash_to_scalar implements the HashToScalar operation for VOPRFs. It returns
44 // one on success and zero on error.
45 hash_to_scalar_func_t hash_to_scalar;
46} VOPRF_METHOD;
47
48static const uint8_t kDefaultAdditionalData[32] = {0};
49
50static int voprf_init_method(VOPRF_METHOD *method, int curve_nid,
51 hash_to_group_func_t hash_to_group,
52 hash_to_scalar_func_t hash_to_scalar) {
53 method->group = EC_GROUP_new_by_curve_name(nid: curve_nid);
54 if (method->group == NULL) {
55 return 0;
56 }
57
58 method->hash_to_group = hash_to_group;
59 method->hash_to_scalar = hash_to_scalar;
60
61 return 1;
62}
63
64static int cbb_add_point(CBB *out, const EC_GROUP *group,
65 const EC_AFFINE *point) {
66 size_t len = ec_point_byte_len(group, form: POINT_CONVERSION_UNCOMPRESSED);
67 if (len == 0) {
68 return 0;
69 }
70
71 uint8_t *p;
72 return CBB_add_space(cbb: out, out_data: &p, len) &&
73 ec_point_to_bytes(group, point, form: POINT_CONVERSION_UNCOMPRESSED, buf: p,
74 max_out: len) == len &&
75 CBB_flush(cbb: out);
76}
77
78static int cbs_get_point(CBS *cbs, const EC_GROUP *group, EC_AFFINE *out) {
79 CBS child;
80 size_t plen = 1 + 2 * BN_num_bytes(bn: &group->field);
81 if (!CBS_get_bytes(cbs, out: &child, len: plen) ||
82 !ec_point_from_uncompressed(group, out, in: CBS_data(cbs: &child),
83 len: CBS_len(cbs: &child))) {
84 return 0;
85 }
86 return 1;
87}
88
89static int scalar_to_cbb(CBB *out, const EC_GROUP *group,
90 const EC_SCALAR *scalar) {
91 uint8_t *buf;
92 size_t scalar_len = BN_num_bytes(bn: &group->order);
93 if (!CBB_add_space(cbb: out, out_data: &buf, len: scalar_len)) {
94 return 0;
95 }
96 ec_scalar_to_bytes(group, out: buf, out_len: &scalar_len, in: scalar);
97 return 1;
98}
99
100static int scalar_from_cbs(CBS *cbs, const EC_GROUP *group, EC_SCALAR *out) {
101 size_t scalar_len = BN_num_bytes(bn: &group->order);
102 CBS tmp;
103 if (!CBS_get_bytes(cbs, out: &tmp, len: scalar_len)) {
104 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
105 return 0;
106 }
107
108 ec_scalar_from_bytes(group, out, in: CBS_data(cbs: &tmp), len: CBS_len(cbs: &tmp));
109 return 1;
110}
111
112static int voprf_calculate_key(const VOPRF_METHOD *method, CBB *out_private,
113 CBB *out_public, const EC_SCALAR *priv) {
114 const EC_GROUP *group = method->group;
115 EC_RAW_POINT pub;
116 EC_AFFINE pub_affine;
117 if (!ec_point_mul_scalar_base(group, r: &pub, scalar: priv) ||
118 !ec_jacobian_to_affine(group, out: &pub_affine, p: &pub)) {
119 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
120 return 0;
121 }
122
123 if (!scalar_to_cbb(out: out_private, group, scalar: priv) ||
124 !cbb_add_point(out: out_public, group, point: &pub_affine)) {
125 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BUFFER_TOO_SMALL);
126 return 0;
127 }
128
129 return 1;
130}
131
132
133static int voprf_generate_key(const VOPRF_METHOD *method, CBB *out_private,
134 CBB *out_public) {
135 EC_SCALAR priv;
136 if (!ec_random_nonzero_scalar(group: method->group, out: &priv, additional_data: kDefaultAdditionalData)) {
137 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
138 return 0;
139 }
140 return voprf_calculate_key(method, out_private, out_public, priv: &priv);
141}
142
143static int voprf_derive_key_from_secret(const VOPRF_METHOD *method,
144 CBB *out_private, CBB *out_public,
145 const uint8_t *secret,
146 size_t secret_len) {
147 static const uint8_t kKeygenLabel[] = "TrustTokenVOPRFKeyGen";
148
149 EC_SCALAR priv;
150 int ok = 0;
151 CBB cbb;
152 CBB_zero(cbb: &cbb);
153 uint8_t *buf = NULL;
154 size_t len;
155 if (!CBB_init(cbb: &cbb, initial_capacity: 0) ||
156 !CBB_add_bytes(cbb: &cbb, data: kKeygenLabel, len: sizeof(kKeygenLabel)) ||
157 !CBB_add_bytes(cbb: &cbb, data: secret, len: secret_len) ||
158 !CBB_finish(cbb: &cbb, out_data: &buf, out_len: &len) ||
159 !method->hash_to_scalar(method->group, &priv, buf, len)) {
160 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
161 goto err;
162 }
163
164 ok = voprf_calculate_key(method, out_private, out_public, priv: &priv);
165
166err:
167 CBB_cleanup(cbb: &cbb);
168 OPENSSL_free(ptr: buf);
169 return ok;
170}
171
172static int voprf_client_key_from_bytes(const VOPRF_METHOD *method,
173 TRUST_TOKEN_CLIENT_KEY *key,
174 const uint8_t *in, size_t len) {
175 const EC_GROUP *group = method->group;
176 if (!ec_point_from_uncompressed(group, out: &key->pubs, in, len)) {
177 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
178 return 0;
179 }
180
181 return 1;
182}
183
184static int voprf_issuer_key_from_bytes(const VOPRF_METHOD *method,
185 TRUST_TOKEN_ISSUER_KEY *key,
186 const uint8_t *in, size_t len) {
187 const EC_GROUP *group = method->group;
188 if (!ec_scalar_from_bytes(group, out: &key->xs, in, len)) {
189 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
190 return 0;
191 }
192
193 // Recompute the public key.
194 EC_RAW_POINT pub;
195 if (!ec_point_mul_scalar_base(group, r: &pub, scalar: &key->xs) ||
196 !ec_jacobian_to_affine(group, out: &key->pubs, p: &pub)) {
197 return 0;
198 }
199
200 return 1;
201}
202
203static STACK_OF(TRUST_TOKEN_PRETOKEN) *voprf_blind(const VOPRF_METHOD *method,
204 CBB *cbb, size_t count,
205 int include_message,
206 const uint8_t *msg,
207 size_t msg_len) {
208 SHA512_CTX hash_ctx;
209
210 const EC_GROUP *group = method->group;
211 STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens =
212 sk_TRUST_TOKEN_PRETOKEN_new_null();
213 if (pretokens == NULL) {
214 goto err;
215 }
216
217 for (size_t i = 0; i < count; i++) {
218 // Insert |pretoken| into |pretokens| early to simplify error-handling.
219 TRUST_TOKEN_PRETOKEN *pretoken =
220 OPENSSL_malloc(size: sizeof(TRUST_TOKEN_PRETOKEN));
221 if (pretoken == NULL ||
222 !sk_TRUST_TOKEN_PRETOKEN_push(sk: pretokens, p: pretoken)) {
223 TRUST_TOKEN_PRETOKEN_free(token: pretoken);
224 goto err;
225 }
226
227 RAND_bytes(buf: pretoken->salt, len: sizeof(pretoken->salt));
228 if (include_message) {
229 assert(SHA512_DIGEST_LENGTH == TRUST_TOKEN_NONCE_SIZE);
230 SHA512_Init(sha: &hash_ctx);
231 SHA512_Update(sha: &hash_ctx, data: pretoken->salt, len: sizeof(pretoken->salt));
232 SHA512_Update(sha: &hash_ctx, data: msg, len: msg_len);
233 SHA512_Final(out: pretoken->t, sha: &hash_ctx);
234 } else {
235 OPENSSL_memcpy(dst: pretoken->t, src: pretoken->salt, TRUST_TOKEN_NONCE_SIZE);
236 }
237
238 // We sample r in Montgomery form to simplify inverting.
239 EC_SCALAR r;
240 if (!ec_random_nonzero_scalar(group, out: &r,
241 additional_data: kDefaultAdditionalData)) {
242 goto err;
243 }
244
245 // pretoken->r is rinv.
246 ec_scalar_inv0_montgomery(group, r: &pretoken->r, a: &r);
247 // Convert both out of Montgomery form.
248 ec_scalar_from_montgomery(group, r: &r, a: &r);
249 ec_scalar_from_montgomery(group, r: &pretoken->r, a: &pretoken->r);
250
251 // Tp is the blinded token in the VOPRF protocol.
252 EC_RAW_POINT P, Tp;
253 if (!method->hash_to_group(group, &P, pretoken->t) ||
254 !ec_point_mul_scalar(group, r: &Tp, p: &P, scalar: &r) ||
255 !ec_jacobian_to_affine(group, out: &pretoken->Tp, p: &Tp)) {
256 goto err;
257 }
258
259 if (!cbb_add_point(out: cbb, group, point: &pretoken->Tp)) {
260 goto err;
261 }
262 }
263
264 return pretokens;
265
266err:
267 sk_TRUST_TOKEN_PRETOKEN_pop_free(sk: pretokens, free_func: TRUST_TOKEN_PRETOKEN_free);
268 return NULL;
269}
270
271static int hash_to_scalar_dleq(const VOPRF_METHOD *method, EC_SCALAR *out,
272 const EC_AFFINE *X, const EC_AFFINE *T,
273 const EC_AFFINE *W, const EC_AFFINE *K0,
274 const EC_AFFINE *K1) {
275 static const uint8_t kDLEQLabel[] = "DLEQ";
276
277 int ok = 0;
278 CBB cbb;
279 CBB_zero(cbb: &cbb);
280 uint8_t *buf = NULL;
281 size_t len;
282 if (!CBB_init(cbb: &cbb, initial_capacity: 0) ||
283 !CBB_add_bytes(cbb: &cbb, data: kDLEQLabel, len: sizeof(kDLEQLabel)) ||
284 !cbb_add_point(out: &cbb, group: method->group, point: X) ||
285 !cbb_add_point(out: &cbb, group: method->group, point: T) ||
286 !cbb_add_point(out: &cbb, group: method->group, point: W) ||
287 !cbb_add_point(out: &cbb, group: method->group, point: K0) ||
288 !cbb_add_point(out: &cbb, group: method->group, point: K1) ||
289 !CBB_finish(cbb: &cbb, out_data: &buf, out_len: &len) ||
290 !method->hash_to_scalar(method->group, out, buf, len)) {
291 goto err;
292 }
293
294 ok = 1;
295
296err:
297 CBB_cleanup(cbb: &cbb);
298 OPENSSL_free(ptr: buf);
299 return ok;
300}
301
302static int hash_to_scalar_batch(const VOPRF_METHOD *method, EC_SCALAR *out,
303 const CBB *points, size_t index) {
304 static const uint8_t kDLEQBatchLabel[] = "DLEQ BATCH";
305 if (index > 0xffff) {
306 // The protocol supports only two-byte batches.
307 OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_OVERFLOW);
308 return 0;
309 }
310
311 int ok = 0;
312 CBB cbb;
313 CBB_zero(cbb: &cbb);
314 uint8_t *buf = NULL;
315 size_t len;
316 if (!CBB_init(cbb: &cbb, initial_capacity: 0) ||
317 !CBB_add_bytes(cbb: &cbb, data: kDLEQBatchLabel, len: sizeof(kDLEQBatchLabel)) ||
318 !CBB_add_bytes(cbb: &cbb, data: CBB_data(cbb: points), len: CBB_len(cbb: points)) ||
319 !CBB_add_u16(cbb: &cbb, value: (uint16_t)index) ||
320 !CBB_finish(cbb: &cbb, out_data: &buf, out_len: &len) ||
321 !method->hash_to_scalar(method->group, out, buf, len)) {
322 goto err;
323 }
324
325 ok = 1;
326
327err:
328 CBB_cleanup(cbb: &cbb);
329 OPENSSL_free(ptr: buf);
330 return ok;
331}
332
333static int dleq_generate(const VOPRF_METHOD *method, CBB *cbb,
334 const TRUST_TOKEN_ISSUER_KEY *priv,
335 const EC_RAW_POINT *T, const EC_RAW_POINT *W) {
336 const EC_GROUP *group = method->group;
337
338 enum {
339 idx_T,
340 idx_W,
341 idx_k0,
342 idx_k1,
343 num_idx,
344 };
345 EC_RAW_POINT jacobians[num_idx];
346
347 // Setup the DLEQ proof.
348 EC_SCALAR r;
349 if (// r <- Zp
350 !ec_random_nonzero_scalar(group, out: &r, additional_data: kDefaultAdditionalData) ||
351 // k0;k1 = r*(G;T)
352 !ec_point_mul_scalar_base(group, r: &jacobians[idx_k0], scalar: &r) ||
353 !ec_point_mul_scalar(group, r: &jacobians[idx_k1], p: T, scalar: &r)) {
354 return 0;
355 }
356
357 EC_AFFINE affines[num_idx];
358 jacobians[idx_T] = *T;
359 jacobians[idx_W] = *W;
360 if (!ec_jacobian_to_affine_batch(group, out: affines, in: jacobians, num: num_idx)) {
361 return 0;
362 }
363
364 // Compute c = Hc(...).
365 EC_SCALAR c;
366 if (!hash_to_scalar_dleq(method, out: &c, X: &priv->pubs, T: &affines[idx_T],
367 W: &affines[idx_W], K0: &affines[idx_k0],
368 K1: &affines[idx_k1])) {
369 return 0;
370 }
371
372
373 EC_SCALAR c_mont;
374 ec_scalar_to_montgomery(group, r: &c_mont, a: &c);
375
376 // u = r + c*xs
377 EC_SCALAR u;
378 ec_scalar_mul_montgomery(group, r: &u, a: &priv->xs, b: &c_mont);
379 ec_scalar_add(group, r: &u, a: &r, b: &u);
380
381 // Store DLEQ proof in transcript.
382 if (!scalar_to_cbb(out: cbb, group, scalar: &c) ||
383 !scalar_to_cbb(out: cbb, group, scalar: &u)) {
384 return 0;
385 }
386
387 return 1;
388}
389
390static int mul_public_2(const EC_GROUP *group, EC_RAW_POINT *out,
391 const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
392 const EC_RAW_POINT *p1, const EC_SCALAR *scalar1) {
393 EC_RAW_POINT points[2] = {*p0, *p1};
394 EC_SCALAR scalars[2] = {*scalar0, *scalar1};
395 return ec_point_mul_scalar_public_batch(group, r: out, /*g_scalar=*/NULL, points,
396 scalars, num: 2);
397}
398
399static int dleq_verify(const VOPRF_METHOD *method, CBS *cbs,
400 const TRUST_TOKEN_CLIENT_KEY *pub, const EC_RAW_POINT *T,
401 const EC_RAW_POINT *W) {
402 const EC_GROUP *group = method->group;
403
404
405 enum {
406 idx_T,
407 idx_W,
408 idx_k0,
409 idx_k1,
410 num_idx,
411 };
412 EC_RAW_POINT jacobians[num_idx];
413
414 // Decode the DLEQ proof.
415 EC_SCALAR c, u;
416 if (!scalar_from_cbs(cbs, group, out: &c) ||
417 !scalar_from_cbs(cbs, group, out: &u)) {
418 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
419 return 0;
420 }
421
422 // k0;k1 = u*(G;T) - c*(pub;W)
423 EC_RAW_POINT pubs;
424 ec_affine_to_jacobian(group, out: &pubs, p: &pub->pubs);
425 EC_SCALAR minus_c;
426 ec_scalar_neg(group, r: &minus_c, a: &c);
427 if (!ec_point_mul_scalar_public(group, r: &jacobians[idx_k0], g_scalar: &u, p: &pubs,
428 p_scalar: &minus_c) ||
429 !mul_public_2(group, out: &jacobians[idx_k1], p0: T, scalar0: &u, p1: W, scalar1: &minus_c)) {
430 return 0;
431 }
432
433 // Check the DLEQ proof.
434 EC_AFFINE affines[num_idx];
435 jacobians[idx_T] = *T;
436 jacobians[idx_W] = *W;
437 if (!ec_jacobian_to_affine_batch(group, out: affines, in: jacobians, num: num_idx)) {
438 return 0;
439 }
440
441 // Compute c = Hc(...).
442 EC_SCALAR calculated;
443 if (!hash_to_scalar_dleq(method, out: &calculated, X: &pub->pubs, T: &affines[idx_T],
444 W: &affines[idx_W], K0: &affines[idx_k0],
445 K1: &affines[idx_k1])) {
446 return 0;
447 }
448
449 // c == calculated
450 if (!ec_scalar_equal_vartime(group, a: &c, b: &calculated)) {
451 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_INVALID_PROOF);
452 return 0;
453 }
454
455 return 1;
456}
457
458static int voprf_sign(const VOPRF_METHOD *method,
459 const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
460 size_t num_requested, size_t num_to_issue) {
461 const EC_GROUP *group = method->group;
462 if (num_requested < num_to_issue) {
463 OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_INTERNAL_ERROR);
464 return 0;
465 }
466
467 if (num_to_issue > ((size_t)-1) / sizeof(EC_RAW_POINT) ||
468 num_to_issue > ((size_t)-1) / sizeof(EC_SCALAR)) {
469 OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_OVERFLOW);
470 return 0;
471 }
472
473 int ret = 0;
474 EC_RAW_POINT *BTs = OPENSSL_malloc(size: num_to_issue * sizeof(EC_RAW_POINT));
475 EC_RAW_POINT *Zs = OPENSSL_malloc(size: num_to_issue * sizeof(EC_RAW_POINT));
476 EC_SCALAR *es = OPENSSL_malloc(size: num_to_issue * sizeof(EC_SCALAR));
477 CBB batch_cbb;
478 CBB_zero(cbb: &batch_cbb);
479 if (!BTs ||
480 !Zs ||
481 !es ||
482 !CBB_init(cbb: &batch_cbb, initial_capacity: 0) ||
483 !cbb_add_point(out: &batch_cbb, group: method->group, point: &key->pubs)) {
484 goto err;
485 }
486
487 for (size_t i = 0; i < num_to_issue; i++) {
488 EC_AFFINE BT_affine, Z_affine;
489 EC_RAW_POINT BT, Z;
490 if (!cbs_get_point(cbs, group, out: &BT_affine)) {
491 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
492 goto err;
493 }
494 ec_affine_to_jacobian(group, out: &BT, p: &BT_affine);
495 if (!ec_point_mul_scalar(group, r: &Z, p: &BT, scalar: &key->xs) ||
496 !ec_jacobian_to_affine(group, out: &Z_affine, p: &Z) ||
497 !cbb_add_point(out: cbb, group, point: &Z_affine)) {
498 goto err;
499 }
500
501 if (!cbb_add_point(out: &batch_cbb, group, point: &BT_affine) ||
502 !cbb_add_point(out: &batch_cbb, group, point: &Z_affine)) {
503 goto err;
504 }
505 BTs[i] = BT;
506 Zs[i] = Z;
507
508 if (!CBB_flush(cbb)) {
509 goto err;
510 }
511 }
512
513 // The DLEQ batching construction is described in appendix B of
514 // https://eprint.iacr.org/2020/072/20200324:214215. Note the additional
515 // computations all act on public inputs.
516 for (size_t i = 0; i < num_to_issue; i++) {
517 if (!hash_to_scalar_batch(method, out: &es[i], points: &batch_cbb, index: i)) {
518 goto err;
519 }
520 }
521
522 EC_RAW_POINT BT_batch, Z_batch;
523 if (!ec_point_mul_scalar_public_batch(group, r: &BT_batch,
524 /*g_scalar=*/NULL, points: BTs, scalars: es,
525 num: num_to_issue) ||
526 !ec_point_mul_scalar_public_batch(group, r: &Z_batch,
527 /*g_scalar=*/NULL, points: Zs, scalars: es,
528 num: num_to_issue)) {
529 goto err;
530 }
531
532 CBB proof;
533 if (!CBB_add_u16_length_prefixed(cbb, out_contents: &proof) ||
534 !dleq_generate(method, cbb: &proof, priv: key, T: &BT_batch, W: &Z_batch) ||
535 !CBB_flush(cbb)) {
536 goto err;
537 }
538
539 // Skip over any unused requests.
540 size_t point_len = 1 + 2 * BN_num_bytes(bn: &group->field);
541 if (!CBS_skip(cbs, len: point_len * (num_requested - num_to_issue))) {
542 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
543 goto err;
544 }
545
546 ret = 1;
547
548err:
549 OPENSSL_free(ptr: BTs);
550 OPENSSL_free(ptr: Zs);
551 OPENSSL_free(ptr: es);
552 CBB_cleanup(cbb: &batch_cbb);
553 return ret;
554}
555
556static STACK_OF(TRUST_TOKEN) *voprf_unblind(
557 const VOPRF_METHOD *method, const TRUST_TOKEN_CLIENT_KEY *key,
558 const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
559 uint32_t key_id) {
560 const EC_GROUP *group = method->group;
561 if (count > sk_TRUST_TOKEN_PRETOKEN_num(sk: pretokens)) {
562 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
563 return NULL;
564 }
565
566 int ok = 0;
567 STACK_OF(TRUST_TOKEN) *ret = sk_TRUST_TOKEN_new_null();
568 if (ret == NULL) {
569 return NULL;
570 }
571
572 if (count > ((size_t)-1) / sizeof(EC_RAW_POINT) ||
573 count > ((size_t)-1) / sizeof(EC_SCALAR)) {
574 OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_OVERFLOW);
575 return 0;
576 }
577 EC_RAW_POINT *BTs = OPENSSL_malloc(size: count * sizeof(EC_RAW_POINT));
578 EC_RAW_POINT *Zs = OPENSSL_malloc(size: count * sizeof(EC_RAW_POINT));
579 EC_SCALAR *es = OPENSSL_malloc(size: count * sizeof(EC_SCALAR));
580 CBB batch_cbb;
581 CBB_zero(cbb: &batch_cbb);
582 if (!BTs ||
583 !Zs ||
584 !es ||
585 !CBB_init(cbb: &batch_cbb, initial_capacity: 0) ||
586 !cbb_add_point(out: &batch_cbb, group: method->group, point: &key->pubs)) {
587 goto err;
588 }
589
590 for (size_t i = 0; i < count; i++) {
591 const TRUST_TOKEN_PRETOKEN *pretoken =
592 sk_TRUST_TOKEN_PRETOKEN_value(sk: pretokens, i);
593
594 EC_AFFINE Z_affine;
595 if (!cbs_get_point(cbs, group, out: &Z_affine)) {
596 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
597 goto err;
598 }
599
600 ec_affine_to_jacobian(group, out: &BTs[i], p: &pretoken->Tp);
601 ec_affine_to_jacobian(group, out: &Zs[i], p: &Z_affine);
602
603 if (!cbb_add_point(out: &batch_cbb, group, point: &pretoken->Tp) ||
604 !cbb_add_point(out: &batch_cbb, group, point: &Z_affine)) {
605 goto err;
606 }
607
608 // Unblind the token.
609 // pretoken->r is rinv.
610 EC_RAW_POINT N;
611 EC_AFFINE N_affine;
612 if (!ec_point_mul_scalar(group, r: &N, p: &Zs[i], scalar: &pretoken->r) ||
613 !ec_jacobian_to_affine(group, out: &N_affine, p: &N)) {
614 goto err;
615 }
616
617 // Serialize the token. Include |key_id| to avoid an extra copy in the layer
618 // above.
619 CBB token_cbb;
620 size_t point_len = 1 + 2 * BN_num_bytes(bn: &group->field);
621 if (!CBB_init(cbb: &token_cbb, initial_capacity: 4 + TRUST_TOKEN_NONCE_SIZE + (2 + point_len)) ||
622 !CBB_add_u32(cbb: &token_cbb, value: key_id) ||
623 !CBB_add_bytes(cbb: &token_cbb, data: pretoken->salt, TRUST_TOKEN_NONCE_SIZE) ||
624 !cbb_add_point(out: &token_cbb, group, point: &N_affine) ||
625 !CBB_flush(cbb: &token_cbb)) {
626 CBB_cleanup(cbb: &token_cbb);
627 goto err;
628 }
629
630 TRUST_TOKEN *token =
631 TRUST_TOKEN_new(data: CBB_data(cbb: &token_cbb), len: CBB_len(cbb: &token_cbb));
632 CBB_cleanup(cbb: &token_cbb);
633 if (token == NULL ||
634 !sk_TRUST_TOKEN_push(sk: ret, p: token)) {
635 TRUST_TOKEN_free(token);
636 goto err;
637 }
638 }
639
640 // The DLEQ batching construction is described in appendix B of
641 // https://eprint.iacr.org/2020/072/20200324:214215. Note the additional
642 // computations all act on public inputs.
643 for (size_t i = 0; i < count; i++) {
644 if (!hash_to_scalar_batch(method, out: &es[i], points: &batch_cbb, index: i)) {
645 goto err;
646 }
647 }
648
649 EC_RAW_POINT BT_batch, Z_batch;
650 if (!ec_point_mul_scalar_public_batch(group, r: &BT_batch,
651 /*g_scalar=*/NULL, points: BTs, scalars: es, num: count) ||
652 !ec_point_mul_scalar_public_batch(group, r: &Z_batch,
653 /*g_scalar=*/NULL, points: Zs, scalars: es, num: count)) {
654 goto err;
655 }
656
657 CBS proof;
658 if (!CBS_get_u16_length_prefixed(cbs, out: &proof) ||
659 !dleq_verify(method, cbs: &proof, pub: key, T: &BT_batch, W: &Z_batch) ||
660 CBS_len(cbs: &proof) != 0) {
661 goto err;
662 }
663
664 ok = 1;
665
666err:
667 OPENSSL_free(ptr: BTs);
668 OPENSSL_free(ptr: Zs);
669 OPENSSL_free(ptr: es);
670 CBB_cleanup(cbb: &batch_cbb);
671 if (!ok) {
672 sk_TRUST_TOKEN_pop_free(sk: ret, free_func: TRUST_TOKEN_free);
673 ret = NULL;
674 }
675 return ret;
676}
677
678static int voprf_read(const VOPRF_METHOD *method,
679 const TRUST_TOKEN_ISSUER_KEY *key,
680 uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
681 const uint8_t *token, size_t token_len,
682 int include_message, const uint8_t *msg, size_t msg_len) {
683 const EC_GROUP *group = method->group;
684 CBS cbs, salt;
685 CBS_init(cbs: &cbs, data: token, len: token_len);
686 EC_AFFINE Ws;
687 if (!CBS_get_bytes(cbs: &cbs, out: &salt, TRUST_TOKEN_NONCE_SIZE) ||
688 !cbs_get_point(cbs: &cbs, group, out: &Ws) ||
689 CBS_len(cbs: &cbs) != 0) {
690 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_INVALID_TOKEN);
691 return 0;
692 }
693
694 if (include_message) {
695 SHA512_CTX hash_ctx;
696 assert(SHA512_DIGEST_LENGTH == TRUST_TOKEN_NONCE_SIZE);
697 SHA512_Init(sha: &hash_ctx);
698 SHA512_Update(sha: &hash_ctx, data: CBS_data(cbs: &salt), len: CBS_len(cbs: &salt));
699 SHA512_Update(sha: &hash_ctx, data: msg, len: msg_len);
700 SHA512_Final(out: out_nonce, sha: &hash_ctx);
701 } else {
702 OPENSSL_memcpy(dst: out_nonce, src: CBS_data(cbs: &salt), n: CBS_len(cbs: &salt));
703 }
704
705
706 EC_RAW_POINT T;
707 if (!method->hash_to_group(group, &T, out_nonce)) {
708 return 0;
709 }
710
711 EC_RAW_POINT Ws_calculated;
712 if (!ec_point_mul_scalar(group, r: &Ws_calculated, p: &T, scalar: &key->xs) ||
713 !ec_affine_jacobian_equal(group, a: &Ws, b: &Ws_calculated)) {
714 OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BAD_VALIDITY_CHECK);
715 return 0;
716 }
717
718 return 1;
719}
720
721
722// VOPRF experiment v2.
723
724static int voprf_exp2_hash_to_group(const EC_GROUP *group, EC_RAW_POINT *out,
725 const uint8_t t[TRUST_TOKEN_NONCE_SIZE]) {
726 const uint8_t kHashTLabel[] = "TrustToken VOPRF Experiment V2 HashToGroup";
727 return ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(
728 group, out, dst: kHashTLabel, dst_len: sizeof(kHashTLabel), msg: t, TRUST_TOKEN_NONCE_SIZE);
729}
730
731static int voprf_exp2_hash_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
732 uint8_t *buf, size_t len) {
733 const uint8_t kHashCLabel[] = "TrustToken VOPRF Experiment V2 HashToScalar";
734 return ec_hash_to_scalar_p384_xmd_sha512_draft07(
735 group, out, dst: kHashCLabel, dst_len: sizeof(kHashCLabel), msg: buf, msg_len: len);
736}
737
738static int voprf_exp2_ok = 0;
739static VOPRF_METHOD voprf_exp2_method;
740static CRYPTO_once_t voprf_exp2_method_once = CRYPTO_ONCE_INIT;
741
742static void voprf_exp2_init_method_impl(void) {
743 voprf_exp2_ok =
744 voprf_init_method(method: &voprf_exp2_method, NID_secp384r1,
745 hash_to_group: voprf_exp2_hash_to_group, hash_to_scalar: voprf_exp2_hash_to_scalar);
746}
747
748static int voprf_exp2_init_method(void) {
749 CRYPTO_once(once: &voprf_exp2_method_once, init: voprf_exp2_init_method_impl);
750 if (!voprf_exp2_ok) {
751 OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_INTERNAL_ERROR);
752 return 0;
753 }
754 return 1;
755}
756
757int voprf_exp2_generate_key(CBB *out_private, CBB *out_public) {
758 if (!voprf_exp2_init_method()) {
759 return 0;
760 }
761
762 return voprf_generate_key(method: &voprf_exp2_method, out_private, out_public);
763}
764
765int voprf_exp2_derive_key_from_secret(CBB *out_private, CBB *out_public,
766 const uint8_t *secret,
767 size_t secret_len) {
768 if (!voprf_exp2_init_method()) {
769 return 0;
770 }
771
772 return voprf_derive_key_from_secret(method: &voprf_exp2_method, out_private,
773 out_public, secret, secret_len);
774}
775
776int voprf_exp2_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
777 const uint8_t *in, size_t len) {
778 if (!voprf_exp2_init_method()) {
779 return 0;
780 }
781 return voprf_client_key_from_bytes(method: &voprf_exp2_method, key, in, len);
782}
783
784int voprf_exp2_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
785 const uint8_t *in, size_t len) {
786 if (!voprf_exp2_init_method()) {
787 return 0;
788 }
789 return voprf_issuer_key_from_bytes(method: &voprf_exp2_method, key, in, len);
790}
791
792STACK_OF(TRUST_TOKEN_PRETOKEN) *voprf_exp2_blind(CBB *cbb, size_t count,
793 int include_message,
794 const uint8_t *msg,
795 size_t msg_len) {
796 if (!voprf_exp2_init_method()) {
797 return NULL;
798 }
799 return voprf_blind(method: &voprf_exp2_method, cbb, count, include_message, msg,
800 msg_len);
801}
802
803int voprf_exp2_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
804 size_t num_requested, size_t num_to_issue,
805 uint8_t private_metadata) {
806 if (!voprf_exp2_init_method() || private_metadata != 0) {
807 return 0;
808 }
809 return voprf_sign(method: &voprf_exp2_method, key, cbb, cbs, num_requested,
810 num_to_issue);
811}
812
813STACK_OF(TRUST_TOKEN) *voprf_exp2_unblind(
814 const TRUST_TOKEN_CLIENT_KEY *key,
815 const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
816 uint32_t key_id) {
817 if (!voprf_exp2_init_method()) {
818 return NULL;
819 }
820 return voprf_unblind(method: &voprf_exp2_method, key, pretokens, cbs, count, key_id);
821}
822
823int voprf_exp2_read(const TRUST_TOKEN_ISSUER_KEY *key,
824 uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
825 uint8_t *out_private_metadata, const uint8_t *token,
826 size_t token_len, int include_message, const uint8_t *msg,
827 size_t msg_len) {
828 if (!voprf_exp2_init_method()) {
829 return 0;
830 }
831 return voprf_read(method: &voprf_exp2_method, key, out_nonce, token, token_len,
832 include_message, msg, msg_len);
833}
834

source code of dart_sdk/third_party/boringssl/src/crypto/trust_token/voprf.c