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