1 /* Copyright (c) 2014, 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 <algorithm>
16 #include <functional>
17 #include <memory>
18 #include <string>
19 #include <vector>
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <openssl/aead.h>
28 #include <openssl/aes.h>
29 #include <openssl/bn.h>
30 #include <openssl/curve25519.h>
31 #include <openssl/crypto.h>
32 #include <openssl/digest.h>
33 #include <openssl/err.h>
34 #include <openssl/ec.h>
35 #include <openssl/ecdsa.h>
36 #include <openssl/ec_key.h>
37 #include <openssl/evp.h>
38 #include <openssl/hrss.h>
39 #include <openssl/mem.h>
40 #include <openssl/nid.h>
41 #include <openssl/rand.h>
42 #include <openssl/rsa.h>
43 #include <openssl/trust_token.h>
44
45 #if defined(OPENSSL_WINDOWS)
46 OPENSSL_MSVC_PRAGMA(warning(push, 3))
47 #include <windows.h>
48 OPENSSL_MSVC_PRAGMA(warning(pop))
49 #elif defined(OPENSSL_APPLE)
50 #include <sys/time.h>
51 #else
52 #include <time.h>
53 #endif
54
55 #include "../crypto/ec_extra/internal.h"
56 #include "../crypto/fipsmodule/ec/internal.h"
57 #include "../crypto/internal.h"
58 #include "../crypto/trust_token/internal.h"
59 #include "internal.h"
60
61 // g_print_json is true if printed output is JSON formatted.
62 static bool g_print_json = false;
63
64 // TimeResults represents the results of benchmarking a function.
65 struct TimeResults {
66 // num_calls is the number of function calls done in the time period.
67 unsigned num_calls;
68 // us is the number of microseconds that elapsed in the time period.
69 unsigned us;
70
PrintTimeResults71 void Print(const std::string &description) const {
72 if (g_print_json) {
73 PrintJSON(description);
74 } else {
75 printf("Did %u %s operations in %uus (%.1f ops/sec)\n", num_calls,
76 description.c_str(), us,
77 (static_cast<double>(num_calls) / us) * 1000000);
78 }
79 }
80
PrintWithBytesTimeResults81 void PrintWithBytes(const std::string &description,
82 size_t bytes_per_call) const {
83 if (g_print_json) {
84 PrintJSON(description, bytes_per_call);
85 } else {
86 printf("Did %u %s operations in %uus (%.1f ops/sec): %.1f MB/s\n",
87 num_calls, description.c_str(), us,
88 (static_cast<double>(num_calls) / us) * 1000000,
89 static_cast<double>(bytes_per_call * num_calls) / us);
90 }
91 }
92
93 private:
PrintJSONTimeResults94 void PrintJSON(const std::string &description,
95 size_t bytes_per_call = 0) const {
96 if (first_json_printed) {
97 puts(",");
98 }
99
100 printf("{\"description\": \"%s\", \"numCalls\": %u, \"microseconds\": %u",
101 description.c_str(), num_calls, us);
102
103 if (bytes_per_call > 0) {
104 printf(", \"bytesPerCall\": %zu", bytes_per_call);
105 }
106
107 printf("}");
108 first_json_printed = true;
109 }
110
111 // first_json_printed is true if |g_print_json| is true and the first item in
112 // the JSON results has been printed already. This is used to handle the
113 // commas between each item in the result list.
114 static bool first_json_printed;
115 };
116
117 bool TimeResults::first_json_printed = false;
118
119 #if defined(OPENSSL_WINDOWS)
time_now()120 static uint64_t time_now() { return GetTickCount64() * 1000; }
121 #elif defined(OPENSSL_APPLE)
time_now()122 static uint64_t time_now() {
123 struct timeval tv;
124 uint64_t ret;
125
126 gettimeofday(&tv, NULL);
127 ret = tv.tv_sec;
128 ret *= 1000000;
129 ret += tv.tv_usec;
130 return ret;
131 }
132 #else
time_now()133 static uint64_t time_now() {
134 struct timespec ts;
135 clock_gettime(CLOCK_MONOTONIC, &ts);
136
137 uint64_t ret = ts.tv_sec;
138 ret *= 1000000;
139 ret += ts.tv_nsec / 1000;
140 return ret;
141 }
142 #endif
143
144 static uint64_t g_timeout_seconds = 1;
145 static std::vector<size_t> g_chunk_lengths = {16, 256, 1350, 8192, 16384};
146
TimeFunction(TimeResults * results,std::function<bool ()> func)147 static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
148 // total_us is the total amount of time that we'll aim to measure a function
149 // for.
150 const uint64_t total_us = g_timeout_seconds * 1000000;
151 uint64_t start = time_now(), now, delta;
152 unsigned done = 0, iterations_between_time_checks;
153
154 if (!func()) {
155 return false;
156 }
157 now = time_now();
158 delta = now - start;
159 if (delta == 0) {
160 iterations_between_time_checks = 250;
161 } else {
162 // Aim for about 100ms between time checks.
163 iterations_between_time_checks =
164 static_cast<double>(100000) / static_cast<double>(delta);
165 if (iterations_between_time_checks > 1000) {
166 iterations_between_time_checks = 1000;
167 } else if (iterations_between_time_checks < 1) {
168 iterations_between_time_checks = 1;
169 }
170 }
171
172 for (;;) {
173 for (unsigned i = 0; i < iterations_between_time_checks; i++) {
174 if (!func()) {
175 return false;
176 }
177 done++;
178 }
179
180 now = time_now();
181 if (now - start > total_us) {
182 break;
183 }
184 }
185
186 results->us = now - start;
187 results->num_calls = done;
188 return true;
189 }
190
SpeedRSA(const std::string & selected)191 static bool SpeedRSA(const std::string &selected) {
192 if (!selected.empty() && selected.find("RSA") == std::string::npos) {
193 return true;
194 }
195
196 static const struct {
197 const char *name;
198 const uint8_t *key;
199 const size_t key_len;
200 } kRSAKeys[] = {
201 {"RSA 2048", kDERRSAPrivate2048, kDERRSAPrivate2048Len},
202 {"RSA 4096", kDERRSAPrivate4096, kDERRSAPrivate4096Len},
203 };
204
205 for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(kRSAKeys); i++) {
206 const std::string name = kRSAKeys[i].name;
207
208 bssl::UniquePtr<RSA> key(
209 RSA_private_key_from_bytes(kRSAKeys[i].key, kRSAKeys[i].key_len));
210 if (key == nullptr) {
211 fprintf(stderr, "Failed to parse %s key.\n", name.c_str());
212 ERR_print_errors_fp(stderr);
213 return false;
214 }
215
216 std::unique_ptr<uint8_t[]> sig(new uint8_t[RSA_size(key.get())]);
217 const uint8_t fake_sha256_hash[32] = {0};
218 unsigned sig_len;
219
220 TimeResults results;
221 if (!TimeFunction(&results,
222 [&key, &sig, &fake_sha256_hash, &sig_len]() -> bool {
223 // Usually during RSA signing we're using a long-lived |RSA| that has
224 // already had all of its |BN_MONT_CTX|s constructed, so it makes
225 // sense to use |key| directly here.
226 return RSA_sign(NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
227 sig.get(), &sig_len, key.get());
228 })) {
229 fprintf(stderr, "RSA_sign failed.\n");
230 ERR_print_errors_fp(stderr);
231 return false;
232 }
233 results.Print(name + " signing");
234
235 if (!TimeFunction(&results,
236 [&key, &fake_sha256_hash, &sig, sig_len]() -> bool {
237 return RSA_verify(
238 NID_sha256, fake_sha256_hash, sizeof(fake_sha256_hash),
239 sig.get(), sig_len, key.get());
240 })) {
241 fprintf(stderr, "RSA_verify failed.\n");
242 ERR_print_errors_fp(stderr);
243 return false;
244 }
245 results.Print(name + " verify (same key)");
246
247 if (!TimeFunction(&results,
248 [&key, &fake_sha256_hash, &sig, sig_len]() -> bool {
249 // Usually during RSA verification we have to parse an RSA key from a
250 // certificate or similar, in which case we'd need to construct a new
251 // RSA key, with a new |BN_MONT_CTX| for the public modulus. If we
252 // were to use |key| directly instead, then these costs wouldn't be
253 // accounted for.
254 bssl::UniquePtr<RSA> verify_key(RSA_new());
255 if (!verify_key) {
256 return false;
257 }
258 verify_key->n = BN_dup(key->n);
259 verify_key->e = BN_dup(key->e);
260 if (!verify_key->n ||
261 !verify_key->e) {
262 return false;
263 }
264 return RSA_verify(NID_sha256, fake_sha256_hash,
265 sizeof(fake_sha256_hash), sig.get(), sig_len,
266 verify_key.get());
267 })) {
268 fprintf(stderr, "RSA_verify failed.\n");
269 ERR_print_errors_fp(stderr);
270 return false;
271 }
272 results.Print(name + " verify (fresh key)");
273 }
274
275 return true;
276 }
277
SpeedRSAKeyGen(const std::string & selected)278 static bool SpeedRSAKeyGen(const std::string &selected) {
279 // Don't run this by default because it's so slow.
280 if (selected != "RSAKeyGen") {
281 return true;
282 }
283
284 bssl::UniquePtr<BIGNUM> e(BN_new());
285 if (!BN_set_word(e.get(), 65537)) {
286 return false;
287 }
288
289 const std::vector<int> kSizes = {2048, 3072, 4096};
290 for (int size : kSizes) {
291 const uint64_t start = time_now();
292 unsigned num_calls = 0;
293 unsigned us;
294 std::vector<unsigned> durations;
295
296 for (;;) {
297 bssl::UniquePtr<RSA> rsa(RSA_new());
298
299 const uint64_t iteration_start = time_now();
300 if (!RSA_generate_key_ex(rsa.get(), size, e.get(), nullptr)) {
301 fprintf(stderr, "RSA_generate_key_ex failed.\n");
302 ERR_print_errors_fp(stderr);
303 return false;
304 }
305 const uint64_t iteration_end = time_now();
306
307 num_calls++;
308 durations.push_back(iteration_end - iteration_start);
309
310 us = iteration_end - start;
311 if (us > 30 * 1000000 /* 30 secs */) {
312 break;
313 }
314 }
315
316 std::sort(durations.begin(), durations.end());
317 const std::string description =
318 std::string("RSA ") + std::to_string(size) + std::string(" key-gen");
319 const TimeResults results = {num_calls, us};
320 results.Print(description);
321 const size_t n = durations.size();
322 assert(n > 0);
323
324 // Distribution information is useful, but doesn't fit into the standard
325 // format used by |g_print_json|.
326 if (!g_print_json) {
327 // |min| and |max| must be stored in temporary variables to avoid an MSVC
328 // bug on x86. There, size_t is a typedef for unsigned, but MSVC's printf
329 // warning tries to retain the distinction and suggest %zu for size_t
330 // instead of %u. It gets confused if std::vector<unsigned> and
331 // std::vector<size_t> are both instantiated. Being typedefs, the two
332 // instantiations are identical, which somehow breaks the size_t vs
333 // unsigned metadata.
334 unsigned min = durations[0];
335 unsigned median = n & 1 ? durations[n / 2]
336 : (durations[n / 2 - 1] + durations[n / 2]) / 2;
337 unsigned max = durations[n - 1];
338 printf(" min: %uus, median: %uus, max: %uus\n", min, median, max);
339 }
340 }
341
342 return true;
343 }
344
align(uint8_t * in,unsigned alignment)345 static uint8_t *align(uint8_t *in, unsigned alignment) {
346 return reinterpret_cast<uint8_t *>(
347 (reinterpret_cast<uintptr_t>(in) + alignment) &
348 ~static_cast<size_t>(alignment - 1));
349 }
350
ChunkLenSuffix(size_t chunk_len)351 static std::string ChunkLenSuffix(size_t chunk_len) {
352 char buf[32];
353 snprintf(buf, sizeof(buf), " (%zu byte%s)", chunk_len,
354 chunk_len != 1 ? "s" : "");
355 return buf;
356 }
357
SpeedAEADChunk(const EVP_AEAD * aead,std::string name,size_t chunk_len,size_t ad_len,evp_aead_direction_t direction)358 static bool SpeedAEADChunk(const EVP_AEAD *aead, std::string name,
359 size_t chunk_len, size_t ad_len,
360 evp_aead_direction_t direction) {
361 static const unsigned kAlignment = 16;
362
363 name += ChunkLenSuffix(chunk_len);
364 bssl::ScopedEVP_AEAD_CTX ctx;
365 const size_t key_len = EVP_AEAD_key_length(aead);
366 const size_t nonce_len = EVP_AEAD_nonce_length(aead);
367 const size_t overhead_len = EVP_AEAD_max_overhead(aead);
368
369 std::unique_ptr<uint8_t[]> key(new uint8_t[key_len]);
370 OPENSSL_memset(key.get(), 0, key_len);
371 std::unique_ptr<uint8_t[]> nonce(new uint8_t[nonce_len]);
372 OPENSSL_memset(nonce.get(), 0, nonce_len);
373 std::unique_ptr<uint8_t[]> in_storage(new uint8_t[chunk_len + kAlignment]);
374 // N.B. for EVP_AEAD_CTX_seal_scatter the input and output buffers may be the
375 // same size. However, in the direction == evp_aead_open case we still use
376 // non-scattering seal, hence we add overhead_len to the size of this buffer.
377 std::unique_ptr<uint8_t[]> out_storage(
378 new uint8_t[chunk_len + overhead_len + kAlignment]);
379 std::unique_ptr<uint8_t[]> in2_storage(
380 new uint8_t[chunk_len + overhead_len + kAlignment]);
381 std::unique_ptr<uint8_t[]> ad(new uint8_t[ad_len]);
382 OPENSSL_memset(ad.get(), 0, ad_len);
383 std::unique_ptr<uint8_t[]> tag_storage(
384 new uint8_t[overhead_len + kAlignment]);
385
386
387 uint8_t *const in = align(in_storage.get(), kAlignment);
388 OPENSSL_memset(in, 0, chunk_len);
389 uint8_t *const out = align(out_storage.get(), kAlignment);
390 OPENSSL_memset(out, 0, chunk_len + overhead_len);
391 uint8_t *const tag = align(tag_storage.get(), kAlignment);
392 OPENSSL_memset(tag, 0, overhead_len);
393 uint8_t *const in2 = align(in2_storage.get(), kAlignment);
394
395 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
396 EVP_AEAD_DEFAULT_TAG_LENGTH,
397 evp_aead_seal)) {
398 fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
399 ERR_print_errors_fp(stderr);
400 return false;
401 }
402
403 TimeResults results;
404 if (direction == evp_aead_seal) {
405 if (!TimeFunction(&results,
406 [chunk_len, nonce_len, ad_len, overhead_len, in, out, tag,
407 &ctx, &nonce, &ad]() -> bool {
408 size_t tag_len;
409 return EVP_AEAD_CTX_seal_scatter(
410 ctx.get(), out, tag, &tag_len, overhead_len,
411 nonce.get(), nonce_len, in, chunk_len, nullptr, 0,
412 ad.get(), ad_len);
413 })) {
414 fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
415 ERR_print_errors_fp(stderr);
416 return false;
417 }
418 } else {
419 size_t out_len;
420 EVP_AEAD_CTX_seal(ctx.get(), out, &out_len, chunk_len + overhead_len,
421 nonce.get(), nonce_len, in, chunk_len, ad.get(), ad_len);
422
423 ctx.Reset();
424 if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
425 EVP_AEAD_DEFAULT_TAG_LENGTH,
426 evp_aead_open)) {
427 fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
428 ERR_print_errors_fp(stderr);
429 return false;
430 }
431
432 if (!TimeFunction(&results,
433 [chunk_len, overhead_len, nonce_len, ad_len, in2, out,
434 out_len, &ctx, &nonce, &ad]() -> bool {
435 size_t in2_len;
436 // N.B. EVP_AEAD_CTX_open_gather is not implemented for
437 // all AEADs.
438 return EVP_AEAD_CTX_open(ctx.get(), in2, &in2_len,
439 chunk_len + overhead_len,
440 nonce.get(), nonce_len, out,
441 out_len, ad.get(), ad_len);
442 })) {
443 fprintf(stderr, "EVP_AEAD_CTX_open failed.\n");
444 ERR_print_errors_fp(stderr);
445 return false;
446 }
447 }
448
449 results.PrintWithBytes(
450 name + (direction == evp_aead_seal ? " seal" : " open"), chunk_len);
451 return true;
452 }
453
SpeedAEAD(const EVP_AEAD * aead,const std::string & name,size_t ad_len,const std::string & selected)454 static bool SpeedAEAD(const EVP_AEAD *aead, const std::string &name,
455 size_t ad_len, const std::string &selected) {
456 if (!selected.empty() && name.find(selected) == std::string::npos) {
457 return true;
458 }
459
460 for (size_t chunk_len : g_chunk_lengths) {
461 if (!SpeedAEADChunk(aead, name, chunk_len, ad_len, evp_aead_seal)) {
462 return false;
463 }
464 }
465 return true;
466 }
467
SpeedAEADOpen(const EVP_AEAD * aead,const std::string & name,size_t ad_len,const std::string & selected)468 static bool SpeedAEADOpen(const EVP_AEAD *aead, const std::string &name,
469 size_t ad_len, const std::string &selected) {
470 if (!selected.empty() && name.find(selected) == std::string::npos) {
471 return true;
472 }
473
474 for (size_t chunk_len : g_chunk_lengths) {
475 if (!SpeedAEADChunk(aead, name, chunk_len, ad_len, evp_aead_open)) {
476 return false;
477 }
478 }
479
480 return true;
481 }
482
SpeedAESBlock(const std::string & name,unsigned bits,const std::string & selected)483 static bool SpeedAESBlock(const std::string &name, unsigned bits,
484 const std::string &selected) {
485 if (!selected.empty() && name.find(selected) == std::string::npos) {
486 return true;
487 }
488
489 static const uint8_t kZero[32] = {0};
490
491 {
492 TimeResults results;
493 if (!TimeFunction(&results, [&]() -> bool {
494 AES_KEY key;
495 return AES_set_encrypt_key(kZero, bits, &key) == 0;
496 })) {
497 fprintf(stderr, "AES_set_encrypt_key failed.\n");
498 return false;
499 }
500 results.Print(name + " encrypt setup");
501 }
502
503 {
504 AES_KEY key;
505 if (AES_set_encrypt_key(kZero, bits, &key) != 0) {
506 return false;
507 }
508 uint8_t block[16] = {0};
509 TimeResults results;
510 if (!TimeFunction(&results, [&]() -> bool {
511 AES_encrypt(block, block, &key);
512 return true;
513 })) {
514 fprintf(stderr, "AES_encrypt failed.\n");
515 return false;
516 }
517 results.Print(name + " encrypt");
518 }
519
520 {
521 TimeResults results;
522 if (!TimeFunction(&results, [&]() -> bool {
523 AES_KEY key;
524 return AES_set_decrypt_key(kZero, bits, &key) == 0;
525 })) {
526 fprintf(stderr, "AES_set_decrypt_key failed.\n");
527 return false;
528 }
529 results.Print(name + " decrypt setup");
530 }
531
532 {
533 AES_KEY key;
534 if (AES_set_decrypt_key(kZero, bits, &key) != 0) {
535 return false;
536 }
537 uint8_t block[16] = {0};
538 TimeResults results;
539 if (!TimeFunction(&results, [&]() -> bool {
540 AES_decrypt(block, block, &key);
541 return true;
542 })) {
543 fprintf(stderr, "AES_decrypt failed.\n");
544 return false;
545 }
546 results.Print(name + " decrypt");
547 }
548
549 return true;
550 }
551
SpeedHashChunk(const EVP_MD * md,std::string name,size_t chunk_len)552 static bool SpeedHashChunk(const EVP_MD *md, std::string name,
553 size_t chunk_len) {
554 bssl::ScopedEVP_MD_CTX ctx;
555 uint8_t scratch[16384];
556
557 if (chunk_len > sizeof(scratch)) {
558 return false;
559 }
560
561 name += ChunkLenSuffix(chunk_len);
562 TimeResults results;
563 if (!TimeFunction(&results, [&ctx, md, chunk_len, &scratch]() -> bool {
564 uint8_t digest[EVP_MAX_MD_SIZE];
565 unsigned int md_len;
566
567 return EVP_DigestInit_ex(ctx.get(), md, NULL /* ENGINE */) &&
568 EVP_DigestUpdate(ctx.get(), scratch, chunk_len) &&
569 EVP_DigestFinal_ex(ctx.get(), digest, &md_len);
570 })) {
571 fprintf(stderr, "EVP_DigestInit_ex failed.\n");
572 ERR_print_errors_fp(stderr);
573 return false;
574 }
575
576 results.PrintWithBytes(name, chunk_len);
577 return true;
578 }
579
SpeedHash(const EVP_MD * md,const std::string & name,const std::string & selected)580 static bool SpeedHash(const EVP_MD *md, const std::string &name,
581 const std::string &selected) {
582 if (!selected.empty() && name.find(selected) == std::string::npos) {
583 return true;
584 }
585
586 for (size_t chunk_len : g_chunk_lengths) {
587 if (!SpeedHashChunk(md, name, chunk_len)) {
588 return false;
589 }
590 }
591
592 return true;
593 }
594
SpeedRandomChunk(std::string name,size_t chunk_len)595 static bool SpeedRandomChunk(std::string name, size_t chunk_len) {
596 uint8_t scratch[16384];
597
598 if (chunk_len > sizeof(scratch)) {
599 return false;
600 }
601
602 name += ChunkLenSuffix(chunk_len);
603 TimeResults results;
604 if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
605 RAND_bytes(scratch, chunk_len);
606 return true;
607 })) {
608 return false;
609 }
610
611 results.PrintWithBytes(name, chunk_len);
612 return true;
613 }
614
SpeedRandom(const std::string & selected)615 static bool SpeedRandom(const std::string &selected) {
616 if (!selected.empty() && selected != "RNG") {
617 return true;
618 }
619
620 for (size_t chunk_len : g_chunk_lengths) {
621 if (!SpeedRandomChunk("RNG", chunk_len)) {
622 return false;
623 }
624 }
625
626 return true;
627 }
628
SpeedECDHCurve(const std::string & name,int nid,const std::string & selected)629 static bool SpeedECDHCurve(const std::string &name, int nid,
630 const std::string &selected) {
631 if (!selected.empty() && name.find(selected) == std::string::npos) {
632 return true;
633 }
634
635 bssl::UniquePtr<EC_KEY> peer_key(EC_KEY_new_by_curve_name(nid));
636 if (!peer_key ||
637 !EC_KEY_generate_key(peer_key.get())) {
638 return false;
639 }
640
641 size_t peer_value_len = EC_POINT_point2oct(
642 EC_KEY_get0_group(peer_key.get()), EC_KEY_get0_public_key(peer_key.get()),
643 POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
644 if (peer_value_len == 0) {
645 return false;
646 }
647 std::unique_ptr<uint8_t[]> peer_value(new uint8_t[peer_value_len]);
648 peer_value_len = EC_POINT_point2oct(
649 EC_KEY_get0_group(peer_key.get()), EC_KEY_get0_public_key(peer_key.get()),
650 POINT_CONVERSION_UNCOMPRESSED, peer_value.get(), peer_value_len, nullptr);
651 if (peer_value_len == 0) {
652 return false;
653 }
654
655 TimeResults results;
656 if (!TimeFunction(&results, [nid, peer_value_len, &peer_value]() -> bool {
657 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
658 if (!key ||
659 !EC_KEY_generate_key(key.get())) {
660 return false;
661 }
662 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
663 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group));
664 bssl::UniquePtr<EC_POINT> peer_point(EC_POINT_new(group));
665 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
666 bssl::UniquePtr<BIGNUM> x(BN_new());
667 if (!point || !peer_point || !ctx || !x ||
668 !EC_POINT_oct2point(group, peer_point.get(), peer_value.get(),
669 peer_value_len, ctx.get()) ||
670 !EC_POINT_mul(group, point.get(), nullptr, peer_point.get(),
671 EC_KEY_get0_private_key(key.get()), ctx.get()) ||
672 !EC_POINT_get_affine_coordinates_GFp(group, point.get(), x.get(),
673 nullptr, ctx.get())) {
674 return false;
675 }
676
677 return true;
678 })) {
679 return false;
680 }
681
682 results.Print(name);
683 return true;
684 }
685
SpeedECDSACurve(const std::string & name,int nid,const std::string & selected)686 static bool SpeedECDSACurve(const std::string &name, int nid,
687 const std::string &selected) {
688 if (!selected.empty() && name.find(selected) == std::string::npos) {
689 return true;
690 }
691
692 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
693 if (!key ||
694 !EC_KEY_generate_key(key.get())) {
695 return false;
696 }
697
698 uint8_t signature[256];
699 if (ECDSA_size(key.get()) > sizeof(signature)) {
700 return false;
701 }
702 uint8_t digest[20];
703 OPENSSL_memset(digest, 42, sizeof(digest));
704 unsigned sig_len;
705
706 TimeResults results;
707 if (!TimeFunction(&results, [&key, &signature, &digest, &sig_len]() -> bool {
708 return ECDSA_sign(0, digest, sizeof(digest), signature, &sig_len,
709 key.get()) == 1;
710 })) {
711 return false;
712 }
713
714 results.Print(name + " signing");
715
716 if (!TimeFunction(&results, [&key, &signature, &digest, sig_len]() -> bool {
717 return ECDSA_verify(0, digest, sizeof(digest), signature, sig_len,
718 key.get()) == 1;
719 })) {
720 return false;
721 }
722
723 results.Print(name + " verify");
724
725 return true;
726 }
727
SpeedECDH(const std::string & selected)728 static bool SpeedECDH(const std::string &selected) {
729 return SpeedECDHCurve("ECDH P-224", NID_secp224r1, selected) &&
730 SpeedECDHCurve("ECDH P-256", NID_X9_62_prime256v1, selected) &&
731 SpeedECDHCurve("ECDH P-384", NID_secp384r1, selected) &&
732 SpeedECDHCurve("ECDH P-521", NID_secp521r1, selected);
733 }
734
SpeedECDSA(const std::string & selected)735 static bool SpeedECDSA(const std::string &selected) {
736 return SpeedECDSACurve("ECDSA P-224", NID_secp224r1, selected) &&
737 SpeedECDSACurve("ECDSA P-256", NID_X9_62_prime256v1, selected) &&
738 SpeedECDSACurve("ECDSA P-384", NID_secp384r1, selected) &&
739 SpeedECDSACurve("ECDSA P-521", NID_secp521r1, selected);
740 }
741
Speed25519(const std::string & selected)742 static bool Speed25519(const std::string &selected) {
743 if (!selected.empty() && selected.find("25519") == std::string::npos) {
744 return true;
745 }
746
747 TimeResults results;
748
749 uint8_t public_key[32], private_key[64];
750
751 if (!TimeFunction(&results, [&public_key, &private_key]() -> bool {
752 ED25519_keypair(public_key, private_key);
753 return true;
754 })) {
755 return false;
756 }
757
758 results.Print("Ed25519 key generation");
759
760 static const uint8_t kMessage[] = {0, 1, 2, 3, 4, 5};
761 uint8_t signature[64];
762
763 if (!TimeFunction(&results, [&private_key, &signature]() -> bool {
764 return ED25519_sign(signature, kMessage, sizeof(kMessage),
765 private_key) == 1;
766 })) {
767 return false;
768 }
769
770 results.Print("Ed25519 signing");
771
772 if (!TimeFunction(&results, [&public_key, &signature]() -> bool {
773 return ED25519_verify(kMessage, sizeof(kMessage), signature,
774 public_key) == 1;
775 })) {
776 fprintf(stderr, "Ed25519 verify failed.\n");
777 return false;
778 }
779
780 results.Print("Ed25519 verify");
781
782 if (!TimeFunction(&results, []() -> bool {
783 uint8_t out[32], in[32];
784 OPENSSL_memset(in, 0, sizeof(in));
785 X25519_public_from_private(out, in);
786 return true;
787 })) {
788 fprintf(stderr, "Curve25519 base-point multiplication failed.\n");
789 return false;
790 }
791
792 results.Print("Curve25519 base-point multiplication");
793
794 if (!TimeFunction(&results, []() -> bool {
795 uint8_t out[32], in1[32], in2[32];
796 OPENSSL_memset(in1, 0, sizeof(in1));
797 OPENSSL_memset(in2, 0, sizeof(in2));
798 in1[0] = 1;
799 in2[0] = 9;
800 return X25519(out, in1, in2) == 1;
801 })) {
802 fprintf(stderr, "Curve25519 arbitrary point multiplication failed.\n");
803 return false;
804 }
805
806 results.Print("Curve25519 arbitrary point multiplication");
807
808 return true;
809 }
810
SpeedSPAKE2(const std::string & selected)811 static bool SpeedSPAKE2(const std::string &selected) {
812 if (!selected.empty() && selected.find("SPAKE2") == std::string::npos) {
813 return true;
814 }
815
816 TimeResults results;
817
818 static const uint8_t kAliceName[] = {'A'};
819 static const uint8_t kBobName[] = {'B'};
820 static const uint8_t kPassword[] = "password";
821 bssl::UniquePtr<SPAKE2_CTX> alice(SPAKE2_CTX_new(spake2_role_alice,
822 kAliceName, sizeof(kAliceName), kBobName,
823 sizeof(kBobName)));
824 uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
825 size_t alice_msg_len;
826
827 if (!SPAKE2_generate_msg(alice.get(), alice_msg, &alice_msg_len,
828 sizeof(alice_msg),
829 kPassword, sizeof(kPassword))) {
830 fprintf(stderr, "SPAKE2_generate_msg failed.\n");
831 return false;
832 }
833
834 if (!TimeFunction(&results, [&alice_msg, alice_msg_len]() -> bool {
835 bssl::UniquePtr<SPAKE2_CTX> bob(SPAKE2_CTX_new(spake2_role_bob,
836 kBobName, sizeof(kBobName), kAliceName,
837 sizeof(kAliceName)));
838 uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE], bob_key[64];
839 size_t bob_msg_len, bob_key_len;
840 if (!SPAKE2_generate_msg(bob.get(), bob_msg, &bob_msg_len,
841 sizeof(bob_msg), kPassword,
842 sizeof(kPassword)) ||
843 !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len,
844 sizeof(bob_key), alice_msg, alice_msg_len)) {
845 return false;
846 }
847
848 return true;
849 })) {
850 fprintf(stderr, "SPAKE2 failed.\n");
851 }
852
853 results.Print("SPAKE2 over Ed25519");
854
855 return true;
856 }
857
SpeedScrypt(const std::string & selected)858 static bool SpeedScrypt(const std::string &selected) {
859 if (!selected.empty() && selected.find("scrypt") == std::string::npos) {
860 return true;
861 }
862
863 TimeResults results;
864
865 static const char kPassword[] = "password";
866 static const uint8_t kSalt[] = "NaCl";
867
868 if (!TimeFunction(&results, [&]() -> bool {
869 uint8_t out[64];
870 return !!EVP_PBE_scrypt(kPassword, sizeof(kPassword) - 1, kSalt,
871 sizeof(kSalt) - 1, 1024, 8, 16, 0 /* max_mem */,
872 out, sizeof(out));
873 })) {
874 fprintf(stderr, "scrypt failed.\n");
875 return false;
876 }
877 results.Print("scrypt (N = 1024, r = 8, p = 16)");
878
879 if (!TimeFunction(&results, [&]() -> bool {
880 uint8_t out[64];
881 return !!EVP_PBE_scrypt(kPassword, sizeof(kPassword) - 1, kSalt,
882 sizeof(kSalt) - 1, 16384, 8, 1, 0 /* max_mem */,
883 out, sizeof(out));
884 })) {
885 fprintf(stderr, "scrypt failed.\n");
886 return false;
887 }
888 results.Print("scrypt (N = 16384, r = 8, p = 1)");
889
890 return true;
891 }
892
SpeedHRSS(const std::string & selected)893 static bool SpeedHRSS(const std::string &selected) {
894 if (!selected.empty() && selected != "HRSS") {
895 return true;
896 }
897
898 TimeResults results;
899
900 if (!TimeFunction(&results, []() -> bool {
901 struct HRSS_public_key pub;
902 struct HRSS_private_key priv;
903 uint8_t entropy[HRSS_GENERATE_KEY_BYTES];
904 RAND_bytes(entropy, sizeof(entropy));
905 HRSS_generate_key(&pub, &priv, entropy);
906 return true;
907 })) {
908 fprintf(stderr, "Failed to time HRSS_generate_key.\n");
909 return false;
910 }
911
912 results.Print("HRSS generate");
913
914 struct HRSS_public_key pub;
915 struct HRSS_private_key priv;
916 uint8_t key_entropy[HRSS_GENERATE_KEY_BYTES];
917 RAND_bytes(key_entropy, sizeof(key_entropy));
918 HRSS_generate_key(&pub, &priv, key_entropy);
919
920 uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES];
921 if (!TimeFunction(&results, [&pub, &ciphertext]() -> bool {
922 uint8_t entropy[HRSS_ENCAP_BYTES];
923 uint8_t shared_key[HRSS_KEY_BYTES];
924 RAND_bytes(entropy, sizeof(entropy));
925 HRSS_encap(ciphertext, shared_key, &pub, entropy);
926 return true;
927 })) {
928 fprintf(stderr, "Failed to time HRSS_encap.\n");
929 return false;
930 }
931
932 results.Print("HRSS encap");
933
934 if (!TimeFunction(&results, [&priv, &ciphertext]() -> bool {
935 uint8_t shared_key[HRSS_KEY_BYTES];
936 HRSS_decap(shared_key, &priv, ciphertext, sizeof(ciphertext));
937 return true;
938 })) {
939 fprintf(stderr, "Failed to time HRSS_encap.\n");
940 return false;
941 }
942
943 results.Print("HRSS decap");
944
945 return true;
946 }
947
SpeedHashToCurve(const std::string & selected)948 static bool SpeedHashToCurve(const std::string &selected) {
949 if (!selected.empty() && selected.find("hashtocurve") == std::string::npos) {
950 return true;
951 }
952
953 uint8_t input[64];
954 RAND_bytes(input, sizeof(input));
955
956 static const uint8_t kLabel[] = "label";
957
958 TimeResults results;
959 {
960 EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp384r1);
961 if (group == NULL) {
962 return false;
963 }
964 if (!TimeFunction(&results, [&]() -> bool {
965 EC_RAW_POINT out;
966 return ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(
967 group, &out, kLabel, sizeof(kLabel), input, sizeof(input));
968 })) {
969 fprintf(stderr, "hash-to-curve failed.\n");
970 return false;
971 }
972 results.Print("hash-to-curve P384_XMD:SHA-512_SSWU_RO_");
973
974 if (!TimeFunction(&results, [&]() -> bool {
975 EC_SCALAR out;
976 return ec_hash_to_scalar_p384_xmd_sha512_draft07(
977 group, &out, kLabel, sizeof(kLabel), input, sizeof(input));
978 })) {
979 fprintf(stderr, "hash-to-scalar failed.\n");
980 return false;
981 }
982 results.Print("hash-to-scalar P384_XMD:SHA-512");
983 }
984
985 return true;
986 }
987
trust_token_pretoken_dup(TRUST_TOKEN_PRETOKEN * in)988 static TRUST_TOKEN_PRETOKEN *trust_token_pretoken_dup(
989 TRUST_TOKEN_PRETOKEN *in) {
990 TRUST_TOKEN_PRETOKEN *out =
991 (TRUST_TOKEN_PRETOKEN *)OPENSSL_malloc(sizeof(TRUST_TOKEN_PRETOKEN));
992 if (out) {
993 OPENSSL_memcpy(out, in, sizeof(TRUST_TOKEN_PRETOKEN));
994 }
995 return out;
996 }
997
SpeedTrustToken(std::string name,const TRUST_TOKEN_METHOD * method,size_t batchsize,const std::string & selected)998 static bool SpeedTrustToken(std::string name, const TRUST_TOKEN_METHOD *method,
999 size_t batchsize, const std::string &selected) {
1000 if (!selected.empty() && selected.find("trusttoken") == std::string::npos) {
1001 return true;
1002 }
1003
1004 TimeResults results;
1005 if (!TimeFunction(&results, [&]() -> bool {
1006 uint8_t priv_key[TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE];
1007 uint8_t pub_key[TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE];
1008 size_t priv_key_len, pub_key_len;
1009 return TRUST_TOKEN_generate_key(
1010 method, priv_key, &priv_key_len, TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE,
1011 pub_key, &pub_key_len, TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0);
1012 })) {
1013 fprintf(stderr, "TRUST_TOKEN_generate_key failed.\n");
1014 return false;
1015 }
1016 results.Print(name + " generate_key");
1017
1018 bssl::UniquePtr<TRUST_TOKEN_CLIENT> client(
1019 TRUST_TOKEN_CLIENT_new(method, batchsize));
1020 bssl::UniquePtr<TRUST_TOKEN_ISSUER> issuer(
1021 TRUST_TOKEN_ISSUER_new(method, batchsize));
1022 uint8_t priv_key[TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE];
1023 uint8_t pub_key[TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE];
1024 size_t priv_key_len, pub_key_len, key_index;
1025 if (!client || !issuer ||
1026 !TRUST_TOKEN_generate_key(
1027 method, priv_key, &priv_key_len, TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE,
1028 pub_key, &pub_key_len, TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0) ||
1029 !TRUST_TOKEN_CLIENT_add_key(client.get(), &key_index, pub_key,
1030 pub_key_len) ||
1031 !TRUST_TOKEN_ISSUER_add_key(issuer.get(), priv_key, priv_key_len)) {
1032 fprintf(stderr, "failed to generate trust token key.\n");
1033 return false;
1034 }
1035
1036 uint8_t public_key[32], private_key[64];
1037 ED25519_keypair(public_key, private_key);
1038 bssl::UniquePtr<EVP_PKEY> priv(
1039 EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, nullptr, private_key, 32));
1040 bssl::UniquePtr<EVP_PKEY> pub(
1041 EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, nullptr, public_key, 32));
1042 if (!priv || !pub) {
1043 fprintf(stderr, "failed to generate trust token SRR key.\n");
1044 return false;
1045 }
1046
1047 TRUST_TOKEN_CLIENT_set_srr_key(client.get(), pub.get());
1048 TRUST_TOKEN_ISSUER_set_srr_key(issuer.get(), priv.get());
1049 uint8_t metadata_key[32];
1050 RAND_bytes(metadata_key, sizeof(metadata_key));
1051 if (!TRUST_TOKEN_ISSUER_set_metadata_key(issuer.get(), metadata_key,
1052 sizeof(metadata_key))) {
1053 fprintf(stderr, "failed to generate trust token metadata key.\n");
1054 return false;
1055 }
1056
1057 if (!TimeFunction(&results, [&]() -> bool {
1058 uint8_t *issue_msg = NULL;
1059 size_t msg_len;
1060 int ok = TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
1061 &msg_len, batchsize);
1062 OPENSSL_free(issue_msg);
1063 // Clear pretokens.
1064 sk_TRUST_TOKEN_PRETOKEN_pop_free(client->pretokens,
1065 TRUST_TOKEN_PRETOKEN_free);
1066 client->pretokens = sk_TRUST_TOKEN_PRETOKEN_new_null();
1067 return ok;
1068 })) {
1069 fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_issuance failed.\n");
1070 return false;
1071 }
1072 results.Print(name + " begin_issuance");
1073
1074 uint8_t *issue_msg = NULL;
1075 size_t msg_len;
1076 if (!TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg, &msg_len,
1077 batchsize)) {
1078 fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_issuance failed.\n");
1079 return false;
1080 }
1081 bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
1082
1083 bssl::UniquePtr<STACK_OF(TRUST_TOKEN_PRETOKEN)> pretokens(
1084 sk_TRUST_TOKEN_PRETOKEN_deep_copy(client->pretokens,
1085 trust_token_pretoken_dup,
1086 TRUST_TOKEN_PRETOKEN_free));
1087
1088 if (!TimeFunction(&results, [&]() -> bool {
1089 uint8_t *issue_resp = NULL;
1090 size_t resp_len, tokens_issued;
1091 int ok = TRUST_TOKEN_ISSUER_issue(issuer.get(), &issue_resp, &resp_len,
1092 &tokens_issued, issue_msg, msg_len,
1093 /*public_metadata=*/0,
1094 /*private_metadata=*/0,
1095 /*max_issuance=*/batchsize);
1096 OPENSSL_free(issue_resp);
1097 return ok;
1098 })) {
1099 fprintf(stderr, "TRUST_TOKEN_ISSUER_issue failed.\n");
1100 return false;
1101 }
1102 results.Print(name + " issue");
1103
1104 uint8_t *issue_resp = NULL;
1105 size_t resp_len, tokens_issued;
1106 if (!TRUST_TOKEN_ISSUER_issue(issuer.get(), &issue_resp, &resp_len,
1107 &tokens_issued, issue_msg, msg_len,
1108 /*public_metadata=*/0, /*private_metadata=*/0,
1109 /*max_issuance=*/batchsize)) {
1110 fprintf(stderr, "TRUST_TOKEN_ISSUER_issue failed.\n");
1111 return false;
1112 }
1113 bssl::UniquePtr<uint8_t> free_issue_resp(issue_resp);
1114
1115 if (!TimeFunction(&results, [&]() -> bool {
1116 size_t key_index2;
1117 bssl::UniquePtr<STACK_OF(TRUST_TOKEN)> tokens(
1118 TRUST_TOKEN_CLIENT_finish_issuance(client.get(), &key_index2,
1119 issue_resp, resp_len));
1120
1121 // Reset pretokens.
1122 client->pretokens = sk_TRUST_TOKEN_PRETOKEN_deep_copy(
1123 pretokens.get(), trust_token_pretoken_dup,
1124 TRUST_TOKEN_PRETOKEN_free);
1125 return !!tokens;
1126 })) {
1127 fprintf(stderr, "TRUST_TOKEN_CLIENT_finish_issuance failed.\n");
1128 return false;
1129 }
1130 results.Print(name + " finish_issuance");
1131
1132 bssl::UniquePtr<STACK_OF(TRUST_TOKEN)> tokens(
1133 TRUST_TOKEN_CLIENT_finish_issuance(client.get(), &key_index, issue_resp,
1134 resp_len));
1135 if (!tokens || sk_TRUST_TOKEN_num(tokens.get()) < 1) {
1136 fprintf(stderr, "TRUST_TOKEN_CLIENT_finish_issuance failed.\n");
1137 return false;
1138 }
1139
1140 const TRUST_TOKEN *token = sk_TRUST_TOKEN_value(tokens.get(), 0);
1141
1142 const uint8_t kClientData[] = "\x70TEST CLIENT DATA";
1143 uint64_t kRedemptionTime = 13374242;
1144
1145 if (!TimeFunction(&results, [&]() -> bool {
1146 uint8_t *redeem_msg = NULL;
1147 size_t redeem_msg_len;
1148 int ok = TRUST_TOKEN_CLIENT_begin_redemption(
1149 client.get(), &redeem_msg, &redeem_msg_len, token, kClientData,
1150 sizeof(kClientData) - 1, kRedemptionTime);
1151 OPENSSL_free(redeem_msg);
1152 return ok;
1153 })) {
1154 fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_redemption failed.\n");
1155 return false;
1156 }
1157 results.Print(name + " begin_redemption");
1158
1159 uint8_t *redeem_msg = NULL;
1160 size_t redeem_msg_len;
1161 if (!TRUST_TOKEN_CLIENT_begin_redemption(
1162 client.get(), &redeem_msg, &redeem_msg_len, token, kClientData,
1163 sizeof(kClientData) - 1, kRedemptionTime)) {
1164 fprintf(stderr, "TRUST_TOKEN_CLIENT_begin_redemption failed.\n");
1165 return false;
1166 }
1167 bssl::UniquePtr<uint8_t> free_redeem_msg(redeem_msg);
1168
1169 if (!TimeFunction(&results, [&]() -> bool {
1170 uint8_t *redeem_resp = NULL;
1171 size_t redeem_resp_len;
1172 TRUST_TOKEN *rtoken = NULL;
1173 uint8_t *client_data = NULL;
1174 size_t client_data_len;
1175 uint64_t redemption_time;
1176 int ok = TRUST_TOKEN_ISSUER_redeem(
1177 issuer.get(), &redeem_resp, &redeem_resp_len, &rtoken, &client_data,
1178 &client_data_len, &redemption_time, redeem_msg, redeem_msg_len,
1179 /*lifetime=*/600);
1180 OPENSSL_free(redeem_resp);
1181 OPENSSL_free(client_data);
1182 TRUST_TOKEN_free(rtoken);
1183 return ok;
1184 })) {
1185 fprintf(stderr, "TRUST_TOKEN_ISSUER_redeem failed.\n");
1186 return false;
1187 }
1188 results.Print(name + " redeem");
1189
1190 uint8_t *redeem_resp = NULL;
1191 size_t redeem_resp_len;
1192 TRUST_TOKEN *rtoken = NULL;
1193 uint8_t *client_data = NULL;
1194 size_t client_data_len;
1195 uint64_t redemption_time;
1196 if (!TRUST_TOKEN_ISSUER_redeem(issuer.get(), &redeem_resp, &redeem_resp_len,
1197 &rtoken, &client_data, &client_data_len,
1198 &redemption_time, redeem_msg, redeem_msg_len,
1199 /*lifetime=*/600)) {
1200 fprintf(stderr, "TRUST_TOKEN_ISSUER_redeem failed.\n");
1201 return false;
1202 }
1203 bssl::UniquePtr<uint8_t> free_redeem_resp(redeem_resp);
1204 bssl::UniquePtr<uint8_t> free_client_data(client_data);
1205 bssl::UniquePtr<TRUST_TOKEN> free_rtoken(rtoken);
1206
1207 if (!TimeFunction(&results, [&]() -> bool {
1208 uint8_t *srr = NULL, *sig = NULL;
1209 size_t srr_len, sig_len;
1210 int ok = TRUST_TOKEN_CLIENT_finish_redemption(
1211 client.get(), &srr, &srr_len, &sig, &sig_len, redeem_resp,
1212 redeem_resp_len);
1213 OPENSSL_free(srr);
1214 OPENSSL_free(sig);
1215 return ok;
1216 })) {
1217 fprintf(stderr, "TRUST_TOKEN_CLIENT_finish_redemption failed.\n");
1218 return false;
1219 }
1220 results.Print(name + " finish_redemption");
1221
1222 return true;
1223 }
1224
1225 #if defined(BORINGSSL_FIPS)
SpeedSelfTest(const std::string & selected)1226 static bool SpeedSelfTest(const std::string &selected) {
1227 if (!selected.empty() && selected.find("self-test") == std::string::npos) {
1228 return true;
1229 }
1230
1231 TimeResults results;
1232 if (!TimeFunction(&results, []() -> bool { return BORINGSSL_self_test(); })) {
1233 fprintf(stderr, "BORINGSSL_self_test faileid.\n");
1234 ERR_print_errors_fp(stderr);
1235 return false;
1236 }
1237
1238 results.Print("self-test");
1239 return true;
1240 }
1241 #endif
1242
1243 static const struct argument kArguments[] = {
1244 {
1245 "-filter",
1246 kOptionalArgument,
1247 "A filter on the speed tests to run",
1248 },
1249 {
1250 "-timeout",
1251 kOptionalArgument,
1252 "The number of seconds to run each test for (default is 1)",
1253 },
1254 {
1255 "-chunks",
1256 kOptionalArgument,
1257 "A comma-separated list of input sizes to run tests at (default is "
1258 "16,256,1350,8192,16384)",
1259 },
1260 {
1261 "-json",
1262 kBooleanArgument,
1263 "If this flag is set, speed will print the output of each benchmark in "
1264 "JSON format as follows: \"{\"description\": "
1265 "\"descriptionOfOperation\", \"numCalls\": 1234, "
1266 "\"timeInMicroseconds\": 1234567, \"bytesPerCall\": 1234}\". When "
1267 "there is no information about the bytes per call for an operation, "
1268 "the JSON field for bytesPerCall will be omitted.",
1269 },
1270 {
1271 "",
1272 kOptionalArgument,
1273 "",
1274 },
1275 };
1276
Speed(const std::vector<std::string> & args)1277 bool Speed(const std::vector<std::string> &args) {
1278 std::map<std::string, std::string> args_map;
1279 if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
1280 PrintUsage(kArguments);
1281 return false;
1282 }
1283
1284 std::string selected;
1285 if (args_map.count("-filter") != 0) {
1286 selected = args_map["-filter"];
1287 }
1288
1289 if (args_map.count("-json") != 0) {
1290 g_print_json = true;
1291 }
1292
1293 if (args_map.count("-timeout") != 0) {
1294 g_timeout_seconds = atoi(args_map["-timeout"].c_str());
1295 }
1296
1297 if (args_map.count("-chunks") != 0) {
1298 g_chunk_lengths.clear();
1299 const char *start = args_map["-chunks"].data();
1300 const char *end = start + args_map["-chunks"].size();
1301 while (start != end) {
1302 errno = 0;
1303 char *ptr;
1304 unsigned long long val = strtoull(start, &ptr, 10);
1305 if (ptr == start /* no numeric characters found */ ||
1306 errno == ERANGE /* overflow */ ||
1307 static_cast<size_t>(val) != val) {
1308 fprintf(stderr, "Error parsing -chunks argument\n");
1309 return false;
1310 }
1311 g_chunk_lengths.push_back(static_cast<size_t>(val));
1312 start = ptr;
1313 if (start != end) {
1314 if (*start != ',') {
1315 fprintf(stderr, "Error parsing -chunks argument\n");
1316 return false;
1317 }
1318 start++;
1319 }
1320 }
1321 }
1322
1323 // kTLSADLen is the number of bytes of additional data that TLS passes to
1324 // AEADs.
1325 static const size_t kTLSADLen = 13;
1326 // kLegacyADLen is the number of bytes that TLS passes to the "legacy" AEADs.
1327 // These are AEADs that weren't originally defined as AEADs, but which we use
1328 // via the AEAD interface. In order for that to work, they have some TLS
1329 // knowledge in them and construct a couple of the AD bytes internally.
1330 static const size_t kLegacyADLen = kTLSADLen - 2;
1331
1332 if (g_print_json) {
1333 puts("[");
1334 }
1335 if (!SpeedRSA(selected) ||
1336 !SpeedAEAD(EVP_aead_aes_128_gcm(), "AES-128-GCM", kTLSADLen, selected) ||
1337 !SpeedAEAD(EVP_aead_aes_256_gcm(), "AES-256-GCM", kTLSADLen, selected) ||
1338 !SpeedAEAD(EVP_aead_chacha20_poly1305(), "ChaCha20-Poly1305", kTLSADLen,
1339 selected) ||
1340 !SpeedAEAD(EVP_aead_des_ede3_cbc_sha1_tls(), "DES-EDE3-CBC-SHA1",
1341 kLegacyADLen, selected) ||
1342 !SpeedAEAD(EVP_aead_aes_128_cbc_sha1_tls(), "AES-128-CBC-SHA1",
1343 kLegacyADLen, selected) ||
1344 !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
1345 kLegacyADLen, selected) ||
1346 !SpeedAEADOpen(EVP_aead_aes_128_cbc_sha1_tls(), "AES-128-CBC-SHA1",
1347 kLegacyADLen, selected) ||
1348 !SpeedAEADOpen(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
1349 kLegacyADLen, selected) ||
1350 !SpeedAEAD(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen,
1351 selected) ||
1352 !SpeedAEAD(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen,
1353 selected) ||
1354 !SpeedAEADOpen(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen,
1355 selected) ||
1356 !SpeedAEADOpen(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen,
1357 selected) ||
1358 !SpeedAEAD(EVP_aead_aes_128_ccm_bluetooth(), "AES-128-CCM-Bluetooth",
1359 kTLSADLen, selected) ||
1360 !SpeedAESBlock("AES-128", 128, selected) ||
1361 !SpeedAESBlock("AES-256", 256, selected) ||
1362 !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
1363 !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
1364 !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
1365 !SpeedHash(EVP_blake2b256(), "BLAKE2b-256", selected) ||
1366 !SpeedRandom(selected) ||
1367 !SpeedECDH(selected) ||
1368 !SpeedECDSA(selected) ||
1369 !Speed25519(selected) ||
1370 !SpeedSPAKE2(selected) ||
1371 !SpeedScrypt(selected) ||
1372 !SpeedRSAKeyGen(selected) ||
1373 !SpeedHRSS(selected) ||
1374 !SpeedHashToCurve(selected) ||
1375 !SpeedTrustToken("TrustToken-Exp1-Batch1", TRUST_TOKEN_experiment_v1(), 1,
1376 selected) ||
1377 !SpeedTrustToken("TrustToken-Exp1-Batch10", TRUST_TOKEN_experiment_v1(),
1378 10, selected) ||
1379 !SpeedTrustToken("TrustToken-Exp2VOPRF-Batch1",
1380 TRUST_TOKEN_experiment_v2_voprf(), 1, selected) ||
1381 !SpeedTrustToken("TrustToken-Exp2VOPRF-Batch10",
1382 TRUST_TOKEN_experiment_v2_voprf(), 10, selected) ||
1383 !SpeedTrustToken("TrustToken-Exp2PMB-Batch1",
1384 TRUST_TOKEN_experiment_v2_pmb(), 1, selected) ||
1385 !SpeedTrustToken("TrustToken-Exp2PMB-Batch10",
1386 TRUST_TOKEN_experiment_v2_pmb(), 10, selected)) {
1387 return false;
1388 }
1389 #if defined(BORINGSSL_FIPS)
1390 if (!SpeedSelfTest(selected)) {
1391 return false;
1392 }
1393 #endif
1394 if (g_print_json) {
1395 puts("\n]");
1396 }
1397
1398 return true;
1399 }
1400