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