1 /* Copyright (c) 2019, 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 <string>
16 #include <vector>
17 
18 #include <assert.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <sys/uio.h>
22 #include <unistd.h>
23 #include <cstdarg>
24 
25 #include <openssl/aes.h>
26 #include <openssl/bn.h>
27 #include <openssl/digest.h>
28 #include <openssl/ec.h>
29 #include <openssl/ec_key.h>
30 #include <openssl/ecdsa.h>
31 #include <openssl/hmac.h>
32 #include <openssl/obj.h>
33 #include <openssl/sha.h>
34 #include <openssl/span.h>
35 
36 #include "../../../../crypto/fipsmodule/rand/internal.h"
37 
38 static constexpr size_t kMaxArgs = 8;
39 static constexpr size_t kMaxArgLength = (1 << 20);
40 static constexpr size_t kMaxNameLength = 30;
41 
42 static_assert((kMaxArgs - 1 * kMaxArgLength) + kMaxNameLength > (1 << 30),
43               "Argument limits permit excessive messages");
44 
45 using namespace bssl;
46 
ReadAll(int fd,void * in_data,size_t data_len)47 static bool ReadAll(int fd, void *in_data, size_t data_len) {
48   uint8_t *data = reinterpret_cast<uint8_t *>(in_data);
49   size_t done = 0;
50 
51   while (done < data_len) {
52     ssize_t r;
53     do {
54       r = read(fd, &data[done], data_len - done);
55     } while (r == -1 && errno == EINTR);
56 
57     if (r <= 0) {
58       return false;
59     }
60 
61     done += r;
62   }
63 
64   return true;
65 }
66 
67 template <typename... Args>
WriteReply(int fd,Args...args)68 static bool WriteReply(int fd, Args... args) {
69   std::vector<Span<const uint8_t>> spans = {args...};
70   if (spans.empty() || spans.size() > kMaxArgs) {
71     abort();
72   }
73 
74   uint32_t nums[1 + kMaxArgs];
75   iovec iovs[kMaxArgs + 1];
76   nums[0] = spans.size();
77   iovs[0].iov_base = nums;
78   iovs[0].iov_len = sizeof(uint32_t) * (1 + spans.size());
79 
80   for (size_t i = 0; i < spans.size(); i++) {
81     const auto &span = spans[i];
82     nums[i + 1] = span.size();
83     iovs[i + 1].iov_base = const_cast<uint8_t *>(span.data());
84     iovs[i + 1].iov_len = span.size();
85   }
86 
87   const size_t num_iov = spans.size() + 1;
88   size_t iov_done = 0;
89   while (iov_done < num_iov) {
90     ssize_t r;
91     do {
92       r = writev(fd, &iovs[iov_done], num_iov - iov_done);
93     } while (r == -1 && errno == EINTR);
94 
95     if (r <= 0) {
96       return false;
97     }
98 
99     size_t written = r;
100     for (size_t i = iov_done; written > 0 && i < num_iov; i++) {
101       iovec &iov = iovs[i];
102 
103       size_t done = written;
104       if (done > iov.iov_len) {
105         done = iov.iov_len;
106       }
107 
108       iov.iov_base = reinterpret_cast<uint8_t *>(iov.iov_base) + done;
109       iov.iov_len -= done;
110       written -= done;
111 
112       if (iov.iov_len == 0) {
113         iov_done++;
114       }
115     }
116 
117     assert(written == 0);
118   }
119 
120   return true;
121 }
122 
GetConfig(const Span<const uint8_t> args[])123 static bool GetConfig(const Span<const uint8_t> args[]) {
124   static constexpr char kConfig[] =
125       R"([
126       {
127         "algorithm": "SHA2-224",
128         "revision": "1.0",
129         "messageLength": [{
130           "min": 0, "max": 65528, "increment": 8
131         }]
132       },
133       {
134         "algorithm": "SHA2-256",
135         "revision": "1.0",
136         "messageLength": [{
137           "min": 0, "max": 65528, "increment": 8
138         }]
139       },
140       {
141         "algorithm": "SHA2-384",
142         "revision": "1.0",
143         "messageLength": [{
144           "min": 0, "max": 65528, "increment": 8
145         }]
146       },
147       {
148         "algorithm": "SHA2-512",
149         "revision": "1.0",
150         "messageLength": [{
151           "min": 0, "max": 65528, "increment": 8
152         }]
153       },
154       {
155         "algorithm": "SHA-1",
156         "revision": "1.0",
157         "messageLength": [{
158           "min": 0, "max": 65528, "increment": 8
159         }]
160       },
161       {
162         "algorithm": "ACVP-AES-ECB",
163         "revision": "1.0",
164         "direction": ["encrypt", "decrypt"],
165         "keyLen": [128, 192, 256]
166       },
167       {
168         "algorithm": "ACVP-AES-CBC",
169         "revision": "1.0",
170         "direction": ["encrypt", "decrypt"],
171         "keyLen": [128, 192, 256]
172       },
173       {
174         "algorithm": "HMAC-SHA-1",
175         "revision": "1.0",
176         "keyLen": [{
177           "min": 8, "max": 2048, "increment": 8
178         }],
179         "macLen": [{
180           "min": 32, "max": 160, "increment": 8
181         }]
182       },
183       {
184         "algorithm": "HMAC-SHA2-224",
185         "revision": "1.0",
186         "keyLen": [{
187           "min": 8, "max": 2048, "increment": 8
188         }],
189         "macLen": [{
190           "min": 32, "max": 224, "increment": 8
191         }]
192       },
193       {
194         "algorithm": "HMAC-SHA2-256",
195         "revision": "1.0",
196         "keyLen": [{
197           "min": 8, "max": 2048, "increment": 8
198         }],
199         "macLen": [{
200           "min": 32, "max": 256, "increment": 8
201         }]
202       },
203       {
204         "algorithm": "HMAC-SHA2-384",
205         "revision": "1.0",
206         "keyLen": [{
207           "min": 8, "max": 2048, "increment": 8
208         }],
209         "macLen": [{
210           "min": 32, "max": 384, "increment": 8
211         }]
212       },
213       {
214         "algorithm": "HMAC-SHA2-512",
215         "revision": "1.0",
216         "keyLen": [{
217           "min": 8, "max": 2048, "increment": 8
218         }],
219         "macLen": [{
220           "min": 32, "max": 512, "increment": 8
221         }]
222       },
223       {
224         "algorithm": "ctrDRBG",
225         "revision": "1.0",
226         "predResistanceEnabled": [false],
227         "reseedImplemented": false,
228         "capabilities": [{
229           "mode": "AES-256",
230           "derFuncEnabled": false,
231           "entropyInputLen": [384],
232           "nonceLen": [0],
233           "persoStringLen": [{"min": 0, "max": 384, "increment": 16}],
234           "additionalInputLen": [
235             {"min": 0, "max": 384, "increment": 16}
236           ],
237           "returnedBitsLen": 2048
238         }]
239       },
240       {
241         "algorithm": "ECDSA",
242         "mode": "keyGen",
243         "revision": "1.0",
244         "curve": [
245           "P-224",
246           "P-256",
247           "P-384",
248           "P-521"
249         ],
250         "secretGenerationMode": [
251           "testing candidates"
252         ]
253       },
254       {
255         "algorithm": "ECDSA",
256         "mode": "keyVer",
257         "revision": "1.0",
258         "curve": [
259           "P-224",
260           "P-256",
261           "P-384",
262           "P-521"
263         ]
264       },
265       {
266         "algorithm": "ECDSA",
267         "mode": "sigGen",
268         "revision": "1.0",
269         "capabilities": [{
270           "curve": [
271             "P-224",
272             "P-256",
273             "P-384",
274             "P-521"
275           ],
276           "hashAlg": [
277             "SHA2-224",
278             "SHA2-256",
279             "SHA2-384",
280             "SHA2-512"
281           ]
282         }]
283       },
284       {
285         "algorithm": "ECDSA",
286         "mode": "sigVer",
287         "revision": "1.0",
288         "capabilities": [{
289           "curve": [
290             "P-224",
291             "P-256",
292             "P-384",
293             "P-521"
294           ],
295           "hashAlg": [
296             "SHA2-224",
297             "SHA2-256",
298             "SHA2-384",
299             "SHA2-512"
300           ]
301         }]
302       }
303     ])";
304   return WriteReply(
305       STDOUT_FILENO,
306       Span<const uint8_t>(reinterpret_cast<const uint8_t *>(kConfig),
307                           sizeof(kConfig) - 1));
308 }
309 
310 template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),
311           size_t DigestLength>
Hash(const Span<const uint8_t> args[])312 static bool Hash(const Span<const uint8_t> args[]) {
313   uint8_t digest[DigestLength];
314   OneShotHash(args[0].data(), args[0].size(), digest);
315   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(digest));
316 }
317 
318 template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
319           void (*Block)(const uint8_t *in, uint8_t *out, const AES_KEY *key)>
AES(const Span<const uint8_t> args[])320 static bool AES(const Span<const uint8_t> args[]) {
321   AES_KEY key;
322   if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
323     return false;
324   }
325   if (args[1].size() % AES_BLOCK_SIZE != 0) {
326     return false;
327   }
328 
329   std::vector<uint8_t> out;
330   out.resize(args[1].size());
331   for (size_t i = 0; i < args[1].size(); i += AES_BLOCK_SIZE) {
332     Block(args[1].data() + i, &out[i], &key);
333   }
334   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
335 }
336 
337 template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
338           int Direction>
AES_CBC(const Span<const uint8_t> args[])339 static bool AES_CBC(const Span<const uint8_t> args[]) {
340   AES_KEY key;
341   if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
342     return false;
343   }
344   if (args[1].size() % AES_BLOCK_SIZE != 0 ||
345       args[2].size() != AES_BLOCK_SIZE) {
346     return false;
347   }
348   uint8_t iv[AES_BLOCK_SIZE];
349   memcpy(iv, args[2].data(), AES_BLOCK_SIZE);
350 
351   std::vector<uint8_t> out;
352   out.resize(args[1].size());
353   AES_cbc_encrypt(args[1].data(), out.data(), args[1].size(), &key, iv,
354                   Direction);
355   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
356 }
357 
358 template <const EVP_MD *HashFunc()>
HMAC(const Span<const uint8_t> args[])359 static bool HMAC(const Span<const uint8_t> args[]) {
360   const EVP_MD *const md = HashFunc();
361   uint8_t digest[EVP_MAX_MD_SIZE];
362   unsigned digest_len;
363   if (::HMAC(md, args[1].data(), args[1].size(), args[0].data(), args[0].size(),
364              digest, &digest_len) == nullptr) {
365     return false;
366   }
367   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(digest, digest_len));
368 }
369 
DRBG(const Span<const uint8_t> args[])370 static bool DRBG(const Span<const uint8_t> args[]) {
371   const auto out_len_bytes = args[0];
372   const auto entropy = args[1];
373   const auto personalisation = args[2];
374   const auto additional_data1 = args[3];
375   const auto additional_data2 = args[4];
376   const auto nonce = args[5];
377 
378   uint32_t out_len;
379   if (out_len_bytes.size() != sizeof(out_len) ||
380       entropy.size() != CTR_DRBG_ENTROPY_LEN ||
381       // nonces are not supported
382       nonce.size() != 0) {
383     return false;
384   }
385   memcpy(&out_len, out_len_bytes.data(), sizeof(out_len));
386   if (out_len > (1 << 24)) {
387     return false;
388   }
389   std::vector<uint8_t> out(out_len);
390 
391   CTR_DRBG_STATE drbg;
392   if (!CTR_DRBG_init(&drbg, entropy.data(), personalisation.data(),
393                      personalisation.size()) ||
394       !CTR_DRBG_generate(&drbg, out.data(), out_len, additional_data1.data(),
395                          additional_data1.size()) ||
396       !CTR_DRBG_generate(&drbg, out.data(), out_len, additional_data2.data(),
397                          additional_data2.size())) {
398     return false;
399   }
400 
401   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
402 }
403 
StringEq(Span<const uint8_t> a,const char * b)404 static bool StringEq(Span<const uint8_t> a, const char *b) {
405   const size_t len = strlen(b);
406   return a.size() == len && memcmp(a.data(), b, len) == 0;
407 }
408 
ECKeyFromName(Span<const uint8_t> name)409 static bssl::UniquePtr<EC_KEY> ECKeyFromName(Span<const uint8_t> name) {
410   int nid;
411   if (StringEq(name, "P-224")) {
412     nid = NID_secp224r1;
413   } else if (StringEq(name, "P-256")) {
414     nid = NID_X9_62_prime256v1;
415   } else if (StringEq(name, "P-384")) {
416     nid = NID_secp384r1;
417   } else if (StringEq(name, "P-521")) {
418     nid = NID_secp521r1;
419   } else {
420     return nullptr;
421   }
422 
423   return bssl::UniquePtr<EC_KEY>(EC_KEY_new_by_curve_name(nid));
424 }
425 
BIGNUMBytes(const BIGNUM * bn)426 static std::vector<uint8_t> BIGNUMBytes(const BIGNUM *bn) {
427   const size_t len = BN_num_bytes(bn);
428   std::vector<uint8_t> ret(len);
429   BN_bn2bin(bn, ret.data());
430   return ret;
431 }
432 
GetPublicKeyBytes(const EC_KEY * key)433 static std::pair<std::vector<uint8_t>, std::vector<uint8_t>> GetPublicKeyBytes(
434     const EC_KEY *key) {
435   bssl::UniquePtr<BIGNUM> x(BN_new());
436   bssl::UniquePtr<BIGNUM> y(BN_new());
437   if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key),
438                                            EC_KEY_get0_public_key(key), x.get(),
439                                            y.get(), /*ctx=*/nullptr)) {
440     abort();
441   }
442 
443   std::vector<uint8_t> x_bytes = BIGNUMBytes(x.get());
444   std::vector<uint8_t> y_bytes = BIGNUMBytes(y.get());
445 
446   return std::make_pair(std::move(x_bytes), std::move(y_bytes));
447 }
448 
ECDSAKeyGen(const Span<const uint8_t> args[])449 static bool ECDSAKeyGen(const Span<const uint8_t> args[]) {
450   bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
451   if (!key || !EC_KEY_generate_key_fips(key.get())) {
452     return false;
453   }
454 
455   const auto pub_key = GetPublicKeyBytes(key.get());
456   std::vector<uint8_t> d_bytes =
457       BIGNUMBytes(EC_KEY_get0_private_key(key.get()));
458 
459   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(d_bytes),
460                     Span<const uint8_t>(pub_key.first),
461                     Span<const uint8_t>(pub_key.second));
462 }
463 
BytesToBIGNUM(Span<const uint8_t> bytes)464 static bssl::UniquePtr<BIGNUM> BytesToBIGNUM(Span<const uint8_t> bytes) {
465   bssl::UniquePtr<BIGNUM> bn(BN_new());
466   BN_bin2bn(bytes.data(), bytes.size(), bn.get());
467   return bn;
468 }
469 
ECDSAKeyVer(const Span<const uint8_t> args[])470 static bool ECDSAKeyVer(const Span<const uint8_t> args[]) {
471   bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
472   if (!key) {
473     return false;
474   }
475 
476   bssl::UniquePtr<BIGNUM> x(BytesToBIGNUM(args[1]));
477   bssl::UniquePtr<BIGNUM> y(BytesToBIGNUM(args[2]));
478 
479   bssl::UniquePtr<EC_POINT> point(EC_POINT_new(EC_KEY_get0_group(key.get())));
480   uint8_t reply[1];
481   if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
482                                            point.get(), x.get(), y.get(),
483                                            /*ctx=*/nullptr) ||
484       !EC_KEY_set_public_key(key.get(), point.get()) ||
485       !EC_KEY_check_fips(key.get())) {
486     reply[0] = 0;
487   } else {
488     reply[0] = 1;
489   }
490 
491   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(reply));
492 }
493 
HashFromName(Span<const uint8_t> name)494 static const EVP_MD *HashFromName(Span<const uint8_t> name) {
495   if (StringEq(name, "SHA2-224")) {
496     return EVP_sha224();
497   } else if (StringEq(name, "SHA2-256")) {
498     return EVP_sha256();
499   } else if (StringEq(name, "SHA2-384")) {
500     return EVP_sha384();
501   } else if (StringEq(name, "SHA2-512")) {
502     return EVP_sha512();
503   } else {
504     return nullptr;
505   }
506 }
507 
ECDSASigGen(const Span<const uint8_t> args[])508 static bool ECDSASigGen(const Span<const uint8_t> args[]) {
509   bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
510   bssl::UniquePtr<BIGNUM> d = BytesToBIGNUM(args[1]);
511   const EVP_MD *hash = HashFromName(args[2]);
512   uint8_t digest[EVP_MAX_MD_SIZE];
513   unsigned digest_len;
514   if (!key || !hash ||
515       !EVP_Digest(args[3].data(), args[3].size(), digest, &digest_len, hash,
516                   /*impl=*/nullptr) ||
517       !EC_KEY_set_private_key(key.get(), d.get())) {
518     return false;
519   }
520 
521   bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_do_sign(digest, digest_len, key.get()));
522   if (!sig) {
523     return false;
524   }
525 
526   std::vector<uint8_t> r_bytes(BIGNUMBytes(sig->r));
527   std::vector<uint8_t> s_bytes(BIGNUMBytes(sig->s));
528 
529   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(r_bytes),
530                     Span<const uint8_t>(s_bytes));
531 }
532 
ECDSASigVer(const Span<const uint8_t> args[])533 static bool ECDSASigVer(const Span<const uint8_t> args[]) {
534   bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
535   const EVP_MD *hash = HashFromName(args[1]);
536   auto msg = args[2];
537   bssl::UniquePtr<BIGNUM> x(BytesToBIGNUM(args[3]));
538   bssl::UniquePtr<BIGNUM> y(BytesToBIGNUM(args[4]));
539   bssl::UniquePtr<BIGNUM> r(BytesToBIGNUM(args[5]));
540   bssl::UniquePtr<BIGNUM> s(BytesToBIGNUM(args[6]));
541   ECDSA_SIG sig;
542   sig.r = r.get();
543   sig.s = s.get();
544 
545   uint8_t digest[EVP_MAX_MD_SIZE];
546   unsigned digest_len;
547   if (!key || !hash ||
548       !EVP_Digest(msg.data(), msg.size(), digest, &digest_len, hash,
549                   /*impl=*/nullptr)) {
550     return false;
551   }
552 
553   bssl::UniquePtr<EC_POINT> point(EC_POINT_new(EC_KEY_get0_group(key.get())));
554   uint8_t reply[1];
555   if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
556                                            point.get(), x.get(), y.get(),
557                                            /*ctx=*/nullptr) ||
558       !EC_KEY_set_public_key(key.get(), point.get()) ||
559       !EC_KEY_check_fips(key.get()) ||
560       !ECDSA_do_verify(digest, digest_len, &sig, key.get())) {
561     reply[0] = 0;
562   } else {
563     reply[0] = 1;
564   }
565 
566   return WriteReply(STDOUT_FILENO, Span<const uint8_t>(reply));
567 }
568 
569 static constexpr struct {
570   const char name[kMaxNameLength + 1];
571   uint8_t expected_args;
572   bool (*handler)(const Span<const uint8_t>[]);
573 } kFunctions[] = {
574     {"getConfig", 0, GetConfig},
575     {"SHA-1", 1, Hash<SHA1, SHA_DIGEST_LENGTH>},
576     {"SHA2-224", 1, Hash<SHA224, SHA224_DIGEST_LENGTH>},
577     {"SHA2-256", 1, Hash<SHA256, SHA256_DIGEST_LENGTH>},
578     {"SHA2-384", 1, Hash<SHA384, SHA256_DIGEST_LENGTH>},
579     {"SHA2-512", 1, Hash<SHA512, SHA512_DIGEST_LENGTH>},
580     {"AES/encrypt", 2, AES<AES_set_encrypt_key, AES_encrypt>},
581     {"AES/decrypt", 2, AES<AES_set_decrypt_key, AES_decrypt>},
582     {"AES-CBC/encrypt", 3, AES_CBC<AES_set_encrypt_key, AES_ENCRYPT>},
583     {"AES-CBC/decrypt", 3, AES_CBC<AES_set_decrypt_key, AES_DECRYPT>},
584     {"HMAC-SHA-1", 2, HMAC<EVP_sha1>},
585     {"HMAC-SHA2-224", 2, HMAC<EVP_sha224>},
586     {"HMAC-SHA2-256", 2, HMAC<EVP_sha256>},
587     {"HMAC-SHA2-384", 2, HMAC<EVP_sha384>},
588     {"HMAC-SHA2-512", 2, HMAC<EVP_sha512>},
589     {"ctrDRBG/AES-256", 6, DRBG},
590     {"ECDSA/keyGen", 1, ECDSAKeyGen},
591     {"ECDSA/keyVer", 3, ECDSAKeyVer},
592     {"ECDSA/sigGen", 4, ECDSASigGen},
593     {"ECDSA/sigVer", 7, ECDSASigVer},
594 };
595 
main()596 int main() {
597   uint32_t nums[1 + kMaxArgs];
598   std::unique_ptr<uint8_t[]> buf;
599   size_t buf_len = 0;
600   Span<const uint8_t> args[kMaxArgs];
601 
602   for (;;) {
603     if (!ReadAll(STDIN_FILENO, nums, sizeof(uint32_t) * 2)) {
604       return 1;
605     }
606 
607     const size_t num_args = nums[0];
608     if (num_args == 0) {
609       fprintf(stderr, "Invalid, zero-argument operation requested.\n");
610       return 2;
611     } else if (num_args > kMaxArgs) {
612       fprintf(stderr,
613               "Operation requested with %zu args, but %zu is the limit.\n",
614               num_args, kMaxArgs);
615       return 2;
616     }
617 
618     if (num_args > 1 &&
619         !ReadAll(STDIN_FILENO, &nums[2], sizeof(uint32_t) * (num_args - 1))) {
620       return 1;
621     }
622 
623     size_t need = 0;
624     for (size_t i = 0; i < num_args; i++) {
625       const size_t arg_length = nums[i + 1];
626       if (i == 0 && arg_length > kMaxNameLength) {
627         fprintf(stderr,
628                 "Operation with name of length %zu exceeded limit of %zu.\n",
629                 arg_length, kMaxNameLength);
630         return 2;
631       } else if (arg_length > kMaxArgLength) {
632         fprintf(
633             stderr,
634             "Operation with argument of length %zu exceeded limit of %zu.\n",
635             arg_length, kMaxArgLength);
636         return 2;
637       }
638 
639       // static_assert around kMaxArgs etc enforces that this doesn't overflow.
640       need += arg_length;
641     }
642 
643     if (need > buf_len) {
644       size_t alloced = need + (need >> 1);
645       if (alloced < need) {
646         abort();
647       }
648       buf.reset(new uint8_t[alloced]);
649       buf_len = alloced;
650     }
651 
652     if (!ReadAll(STDIN_FILENO, buf.get(), need)) {
653       return 1;
654     }
655 
656     size_t offset = 0;
657     for (size_t i = 0; i < num_args; i++) {
658       args[i] = Span<const uint8_t>(&buf[offset], nums[i + 1]);
659       offset += nums[i + 1];
660     }
661 
662     bool found = true;
663     for (const auto &func : kFunctions) {
664       if (args[0].size() == strlen(func.name) &&
665           memcmp(args[0].data(), func.name, args[0].size()) == 0) {
666         if (num_args - 1 != func.expected_args) {
667           fprintf(stderr,
668                   "\'%s\' operation received %zu arguments but expected %u.\n",
669                   func.name, num_args - 1, func.expected_args);
670           return 2;
671         }
672 
673         if (!func.handler(&args[1])) {
674           return 4;
675         }
676 
677         found = true;
678         break;
679       }
680     }
681 
682     if (!found) {
683       const std::string name(reinterpret_cast<const char *>(args[0].data()),
684                              args[0].size());
685       fprintf(stderr, "Unknown operation: %s\n", name.c_str());
686       return 3;
687     }
688   }
689 }
690