blob: d42d127b03a1d30f5bcddfb4275187fa1c3358cb [file] [log] [blame]
David Benjamin6f415952024-12-10 21:28:37 -05001/* Copyright 2019 The BoringSSL Authors
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002 *
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
Adam Langleye44d9772020-10-22 16:21:09 -070015#include <map>
Adam Langley830e7862024-11-21 16:32:38 -080016#include <memory>
Adam Langley4ca15d52019-10-08 15:48:40 -070017#include <string>
Adam Langleyb7f0c1b2019-07-09 18:02:14 -070018#include <vector>
19
20#include <assert.h>
Adam Langley4ca15d52019-10-08 15:48:40 -070021#include <errno.h>
Adam Langley81658a92020-09-29 14:54:09 -070022#include <limits.h>
Adam Langleyb7f0c1b2019-07-09 18:02:14 -070023#include <string.h>
24#include <sys/uio.h>
25#include <unistd.h>
26#include <cstdarg>
27
Adam Langleyfda92cd2020-09-29 11:00:51 -070028#include <openssl/aead.h>
Adam Langley974f4dd2019-08-01 17:20:31 -070029#include <openssl/aes.h>
Gurleen Grewal913a2402019-11-08 18:09:41 -080030#include <openssl/bn.h>
Adam Langley830e7862024-11-21 16:32:38 -080031#include <openssl/bytestring.h>
Adam Langleye796cc62020-10-07 14:48:48 -070032#include <openssl/cipher.h>
Adam Langleyfb0c05c2020-07-01 13:23:55 -070033#include <openssl/cmac.h>
Adam Langley24c01862022-05-06 16:14:47 -070034#include <openssl/ctrdrbg.h>
Adam Langley28cab642020-12-10 06:59:26 -080035#include <openssl/dh.h>
Gurleen Grewal2085c7c2019-10-25 13:20:17 -070036#include <openssl/digest.h>
Gurleen Grewal913a2402019-11-08 18:09:41 -080037#include <openssl/ec.h>
38#include <openssl/ec_key.h>
Adam Langley0898b072020-12-08 13:44:02 -080039#include <openssl/ecdh.h>
Gurleen Grewal913a2402019-11-08 18:09:41 -080040#include <openssl/ecdsa.h>
Adam Langley777e1ff2020-10-22 16:57:56 -070041#include <openssl/err.h>
Adam Langleyd3acd452023-04-12 23:03:11 +000042#include <openssl/hkdf.h>
Gurleen Grewal2085c7c2019-10-25 13:20:17 -070043#include <openssl/hmac.h>
Gurleen Grewal913a2402019-11-08 18:09:41 -080044#include <openssl/obj.h>
Adam Langley2e22d1b2020-10-22 07:56:36 -070045#include <openssl/rsa.h>
Adam Langleyb7f0c1b2019-07-09 18:02:14 -070046#include <openssl/sha.h>
47#include <openssl/span.h>
48
Adam Langley830e7862024-11-21 16:32:38 -080049#include "../../../../crypto/fipsmodule/bcm_interface.h"
Adam Langley0898b072020-12-08 13:44:02 -080050#include "../../../../crypto/fipsmodule/ec/internal.h"
Gurleen Grewal92943062019-11-04 16:10:55 -080051#include "../../../../crypto/fipsmodule/rand/internal.h"
Adam Langleyf0400012020-12-07 15:06:13 -080052#include "../../../../crypto/fipsmodule/tls/internal.h"
Stephen Cranebc0a4f12021-02-12 15:12:29 -080053#include "modulewrapper.h"
Gurleen Grewal92943062019-11-04 16:10:55 -080054
Adam Langleyb7f0c1b2019-07-09 18:02:14 -070055
Stephen Cranebc0a4f12021-02-12 15:12:29 -080056namespace bssl {
57namespace acvp {
Adam Langleyb7f0c1b2019-07-09 18:02:14 -070058
Stephen Cranebc0a4f12021-02-12 15:12:29 -080059#if defined(OPENSSL_TRUSTY)
60#include <trusty_log.h>
61#define LOG_ERROR(...) TLOGE(__VA_ARGS__)
Pete Bentleycc509bd2021-09-28 20:41:03 +010062#define TLOG_TAG "modulewrapper"
Stephen Cranebc0a4f12021-02-12 15:12:29 -080063#else
64#define LOG_ERROR(...) fprintf(stderr, __VA_ARGS__)
65#endif // OPENSSL_TRUSTY
66
67constexpr size_t kMaxArgLength = (1 << 20);
68
69RequestBuffer::~RequestBuffer() = default;
70
71class RequestBufferImpl : public RequestBuffer {
72 public:
73 ~RequestBufferImpl() = default;
74
75 std::vector<uint8_t> buf;
76 Span<const uint8_t> args[kMaxArgs];
77};
78
79// static
80std::unique_ptr<RequestBuffer> RequestBuffer::New() {
David Benjamina36ac0a2023-07-04 12:48:02 -040081 return std::make_unique<RequestBufferImpl>();
Stephen Cranebc0a4f12021-02-12 15:12:29 -080082}
Adam Langleyb7f0c1b2019-07-09 18:02:14 -070083
84static bool ReadAll(int fd, void *in_data, size_t data_len) {
85 uint8_t *data = reinterpret_cast<uint8_t *>(in_data);
86 size_t done = 0;
87
88 while (done < data_len) {
89 ssize_t r;
90 do {
91 r = read(fd, &data[done], data_len - done);
92 } while (r == -1 && errno == EINTR);
93
94 if (r <= 0) {
95 return false;
96 }
97
98 done += r;
99 }
100
101 return true;
102}
103
Stephen Cranebc0a4f12021-02-12 15:12:29 -0800104Span<const Span<const uint8_t>> ParseArgsFromFd(int fd,
105 RequestBuffer *in_buffer) {
106 RequestBufferImpl *buffer = reinterpret_cast<RequestBufferImpl *>(in_buffer);
107 uint32_t nums[1 + kMaxArgs];
108 const Span<const Span<const uint8_t>> empty_span;
109
110 if (!ReadAll(fd, nums, sizeof(uint32_t) * 2)) {
111 return empty_span;
112 }
113
114 const size_t num_args = nums[0];
115 if (num_args == 0) {
116 LOG_ERROR("Invalid, zero-argument operation requested.\n");
117 return empty_span;
118 } else if (num_args > kMaxArgs) {
119 LOG_ERROR("Operation requested with %zu args, but %zu is the limit.\n",
120 num_args, kMaxArgs);
121 return empty_span;
122 }
123
124 if (num_args > 1 &&
125 !ReadAll(fd, &nums[2], sizeof(uint32_t) * (num_args - 1))) {
126 return empty_span;
127 }
128
129 size_t need = 0;
130 for (size_t i = 0; i < num_args; i++) {
131 const size_t arg_length = nums[i + 1];
132 if (i == 0 && arg_length > kMaxNameLength) {
133 LOG_ERROR("Operation with name of length %zu exceeded limit of %zu.\n",
134 arg_length, kMaxNameLength);
135 return empty_span;
136 } else if (arg_length > kMaxArgLength) {
137 LOG_ERROR(
138 "Operation with argument of length %zu exceeded limit of %zu.\n",
139 arg_length, kMaxArgLength);
140 return empty_span;
141 }
142
143 // This static_assert confirms that the following addition doesn't
144 // overflow.
145 static_assert((kMaxArgs - 1 * kMaxArgLength) + kMaxNameLength > (1 << 30),
146 "Argument limits permit excessive messages");
147 need += arg_length;
148 }
149
150 if (need > buffer->buf.size()) {
151 size_t alloced = need + (need >> 1);
152 if (alloced < need) {
153 abort();
154 }
155 buffer->buf.resize(alloced);
156 }
157
158 if (!ReadAll(fd, buffer->buf.data(), need)) {
159 return empty_span;
160 }
161
162 size_t offset = 0;
163 for (size_t i = 0; i < num_args; i++) {
164 buffer->args[i] = Span<const uint8_t>(&buffer->buf[offset], nums[i + 1]);
165 offset += nums[i + 1];
166 }
167
168 return Span<const Span<const uint8_t>>(buffer->args, num_args);
169}
170
Adam Langleye24491a2022-11-25 21:23:03 +0000171// g_reply_buffer contains buffered replies which will be flushed when acvp
172// requests.
173static std::vector<uint8_t> g_reply_buffer;
174
175bool WriteReplyToBuffer(const std::vector<Span<const uint8_t>> &spans) {
176 if (spans.size() > kMaxArgs) {
177 abort();
178 }
179
180 uint8_t buf[4];
181 CRYPTO_store_u32_le(buf, spans.size());
182 g_reply_buffer.insert(g_reply_buffer.end(), buf, buf + sizeof(buf));
183 for (const auto &span : spans) {
184 CRYPTO_store_u32_le(buf, span.size());
185 g_reply_buffer.insert(g_reply_buffer.end(), buf, buf + sizeof(buf));
186 }
187 for (const auto &span : spans) {
188 g_reply_buffer.insert(g_reply_buffer.end(), span.begin(), span.end());
189 }
190
191 return true;
192}
193
194bool FlushBuffer(int fd) {
195 size_t done = 0;
196
197 while (done < g_reply_buffer.size()) {
198 ssize_t n;
199 do {
200 n = write(fd, g_reply_buffer.data() + done, g_reply_buffer.size() - done);
201 } while (n < 0 && errno == EINTR);
202
203 if (n < 0) {
204 return false;
205 }
206 done += static_cast<size_t>(n);
207 }
208
209 g_reply_buffer.clear();
210
211 return true;
212}
213
Stephen Cranebc0a4f12021-02-12 15:12:29 -0800214bool WriteReplyToFd(int fd, const std::vector<Span<const uint8_t>> &spans) {
Adam Langleye24491a2022-11-25 21:23:03 +0000215 if (spans.size() > kMaxArgs) {
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700216 abort();
217 }
218
219 uint32_t nums[1 + kMaxArgs];
220 iovec iovs[kMaxArgs + 1];
221 nums[0] = spans.size();
222 iovs[0].iov_base = nums;
223 iovs[0].iov_len = sizeof(uint32_t) * (1 + spans.size());
224
Adam Langley437eabd2020-09-29 10:55:09 -0700225 size_t num_iov = 1;
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700226 for (size_t i = 0; i < spans.size(); i++) {
227 const auto &span = spans[i];
228 nums[i + 1] = span.size();
David Benjaminfd835922020-10-20 17:26:24 -0400229 if (span.empty()) {
Adam Langley437eabd2020-09-29 10:55:09 -0700230 continue;
231 }
232
233 iovs[num_iov].iov_base = const_cast<uint8_t *>(span.data());
234 iovs[num_iov].iov_len = span.size();
235 num_iov++;
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700236 }
237
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700238 size_t iov_done = 0;
239 while (iov_done < num_iov) {
240 ssize_t r;
241 do {
242 r = writev(fd, &iovs[iov_done], num_iov - iov_done);
243 } while (r == -1 && errno == EINTR);
244
245 if (r <= 0) {
246 return false;
247 }
248
249 size_t written = r;
Adam Langley437eabd2020-09-29 10:55:09 -0700250 for (size_t i = iov_done; i < num_iov && written > 0; i++) {
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700251 iovec &iov = iovs[i];
252
253 size_t done = written;
254 if (done > iov.iov_len) {
255 done = iov.iov_len;
256 }
257
258 iov.iov_base = reinterpret_cast<uint8_t *>(iov.iov_base) + done;
259 iov.iov_len -= done;
260 written -= done;
261
262 if (iov.iov_len == 0) {
263 iov_done++;
264 }
265 }
266
267 assert(written == 0);
268 }
269
270 return true;
271}
272
Adam Langley830e7862024-11-21 16:32:38 -0800273static bool GetConfig(const Span<const uint8_t> args[],
274 ReplyCallback write_reply) {
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700275 static constexpr char kConfig[] =
Adam Langley279740e2019-11-05 11:40:27 -0800276 R"([
277 {
Adam Langleye24491a2022-11-25 21:23:03 +0000278 "algorithm": "acvptool",
279 "features": ["batch"]
280 },
281 {
Adam Langley279740e2019-11-05 11:40:27 -0800282 "algorithm": "SHA2-224",
283 "revision": "1.0",
284 "messageLength": [{
285 "min": 0, "max": 65528, "increment": 8
286 }]
287 },
288 {
289 "algorithm": "SHA2-256",
290 "revision": "1.0",
291 "messageLength": [{
292 "min": 0, "max": 65528, "increment": 8
293 }]
294 },
295 {
296 "algorithm": "SHA2-384",
297 "revision": "1.0",
298 "messageLength": [{
299 "min": 0, "max": 65528, "increment": 8
300 }]
301 },
302 {
303 "algorithm": "SHA2-512",
304 "revision": "1.0",
305 "messageLength": [{
306 "min": 0, "max": 65528, "increment": 8
307 }]
308 },
309 {
Adam Langley806c5052020-11-19 10:18:19 -0800310 "algorithm": "SHA2-512/256",
311 "revision": "1.0",
312 "messageLength": [{
313 "min": 0, "max": 65528, "increment": 8
314 }]
315 },
316 {
Adam Langley279740e2019-11-05 11:40:27 -0800317 "algorithm": "SHA-1",
318 "revision": "1.0",
319 "messageLength": [{
320 "min": 0, "max": 65528, "increment": 8
321 }]
322 },
323 {
324 "algorithm": "ACVP-AES-ECB",
325 "revision": "1.0",
326 "direction": ["encrypt", "decrypt"],
327 "keyLen": [128, 192, 256]
328 },
329 {
Adam Langley67818be2020-09-29 10:59:35 -0700330 "algorithm": "ACVP-AES-CTR",
331 "revision": "1.0",
332 "direction": ["encrypt", "decrypt"],
333 "keyLen": [128, 192, 256],
334 "payloadLen": [{
335 "min": 8, "max": 128, "increment": 8
336 }],
337 "incrementalCounter": true,
338 "overflowCounter": true,
339 "performCounterTests": true
340 },
341 {
Adam Langley279740e2019-11-05 11:40:27 -0800342 "algorithm": "ACVP-AES-CBC",
343 "revision": "1.0",
344 "direction": ["encrypt", "decrypt"],
345 "keyLen": [128, 192, 256]
346 },
347 {
Adam Langleyfda92cd2020-09-29 11:00:51 -0700348 "algorithm": "ACVP-AES-GCM",
349 "revision": "1.0",
350 "direction": ["encrypt", "decrypt"],
Adam Langley8f4e9d42024-01-11 18:03:59 +0000351 "keyLen": [128, 256],
Adam Langleyfda92cd2020-09-29 11:00:51 -0700352 "payloadLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700353 "min": 0, "max": 65536, "increment": 8
Adam Langleyfda92cd2020-09-29 11:00:51 -0700354 }],
355 "aadLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700356 "min": 0, "max": 65536, "increment": 8
Adam Langleyfda92cd2020-09-29 11:00:51 -0700357 }],
Adam Langley9ac743e2020-12-07 15:05:53 -0800358 "tagLen": [32, 64, 96, 104, 112, 120, 128],
Adam Langleyfda92cd2020-09-29 11:00:51 -0700359 "ivLen": [96],
Adam Langley8f4e9d42024-01-11 18:03:59 +0000360 "ivGen": "internal",
361 "ivGenMode": "8.2.2"
Adam Langleyfda92cd2020-09-29 11:00:51 -0700362 },
363 {
Adam Langleyb8912d72024-05-14 19:54:45 +0000364 "algorithm": "ACVP-AES-GCM",
365 "revision": "1.0",
366 "direction": ["encrypt", "decrypt"],
367 "keyLen": [128, 192, 256],
368 "payloadLen": [{
369 "min": 0, "max": 65536, "increment": 8
370 }],
371 "aadLen": [{
372 "min": 0, "max": 65536, "increment": 8
373 }],
374 "tagLen": [32, 64, 96, 104, 112, 120, 128],
375 "ivLen": [96],
376 "ivGen": "external"
377 },
378 {
Adam Langley7a1986c2021-04-14 16:11:54 -0700379 "algorithm": "ACVP-AES-GMAC",
380 "revision": "1.0",
381 "direction": ["encrypt", "decrypt"],
382 "keyLen": [128, 192, 256],
383 "payloadLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700384 "min": 0, "max": 65536, "increment": 8
Adam Langley7a1986c2021-04-14 16:11:54 -0700385 }],
386 "aadLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700387 "min": 0, "max": 65536, "increment": 8
Adam Langley7a1986c2021-04-14 16:11:54 -0700388 }],
389 "tagLen": [32, 64, 96, 104, 112, 120, 128],
390 "ivLen": [96],
391 "ivGen": "external"
392 },
393 {
Adam Langley81658a92020-09-29 14:54:09 -0700394 "algorithm": "ACVP-AES-KW",
395 "revision": "1.0",
396 "direction": [
397 "encrypt",
398 "decrypt"
399 ],
400 "kwCipher": [
401 "cipher"
402 ],
403 "keyLen": [
404 128, 192, 256
405 ],
Adam Langley828b2d22022-05-30 16:36:40 -0700406 "payloadLen": [{"min": 128, "max": 4096, "increment": 64}]
Adam Langley81658a92020-09-29 14:54:09 -0700407 },
408 {
Adam Langleyb117a3a2020-09-29 15:36:52 -0700409 "algorithm": "ACVP-AES-KWP",
410 "revision": "1.0",
411 "direction": [
412 "encrypt",
413 "decrypt"
414 ],
415 "kwCipher": [
416 "cipher"
417 ],
418 "keyLen": [
419 128, 192, 256
420 ],
Adam Langley9ac743e2020-12-07 15:05:53 -0800421 "payloadLen": [{"min": 8, "max": 4096, "increment": 8}]
Adam Langleyb117a3a2020-09-29 15:36:52 -0700422 },
423 {
Adam Langleyf94e6d72020-10-02 14:04:37 -0700424 "algorithm": "ACVP-AES-CCM",
425 "revision": "1.0",
426 "direction": [
427 "encrypt",
428 "decrypt"
429 ],
430 "keyLen": [
431 128
432 ],
433 "payloadLen": [{"min": 0, "max": 256, "increment": 8}],
434 "ivLen": [104],
Adam Langley828b2d22022-05-30 16:36:40 -0700435 "tagLen": [32, 64],
436 "aadLen": [{"min": 0, "max": 524288, "increment": 8}]
Adam Langleyf94e6d72020-10-02 14:04:37 -0700437 },
438 {
Adam Langley279740e2019-11-05 11:40:27 -0800439 "algorithm": "HMAC-SHA-1",
440 "revision": "1.0",
441 "keyLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700442 "min": 8, "max": 524288, "increment": 8
Adam Langley279740e2019-11-05 11:40:27 -0800443 }],
444 "macLen": [{
445 "min": 32, "max": 160, "increment": 8
446 }]
447 },
448 {
449 "algorithm": "HMAC-SHA2-224",
450 "revision": "1.0",
451 "keyLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700452 "min": 8, "max": 524288, "increment": 8
Adam Langley279740e2019-11-05 11:40:27 -0800453 }],
454 "macLen": [{
455 "min": 32, "max": 224, "increment": 8
456 }]
457 },
458 {
459 "algorithm": "HMAC-SHA2-256",
460 "revision": "1.0",
461 "keyLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700462 "min": 8, "max": 524288, "increment": 8
Adam Langley279740e2019-11-05 11:40:27 -0800463 }],
464 "macLen": [{
465 "min": 32, "max": 256, "increment": 8
466 }]
467 },
468 {
469 "algorithm": "HMAC-SHA2-384",
470 "revision": "1.0",
471 "keyLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700472 "min": 8, "max": 524288, "increment": 8
Adam Langley279740e2019-11-05 11:40:27 -0800473 }],
474 "macLen": [{
475 "min": 32, "max": 384, "increment": 8
476 }]
477 },
478 {
479 "algorithm": "HMAC-SHA2-512",
480 "revision": "1.0",
481 "keyLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700482 "min": 8, "max": 524288, "increment": 8
Adam Langley279740e2019-11-05 11:40:27 -0800483 }],
484 "macLen": [{
485 "min": 32, "max": 512, "increment": 8
486 }]
487 },
488 {
Adam Langley097ffe12022-05-04 15:27:12 -0700489 "algorithm": "HMAC-SHA2-512/256",
490 "revision": "1.0",
491 "keyLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700492 "min": 8, "max": 524288, "increment": 8
Adam Langley097ffe12022-05-04 15:27:12 -0700493 }],
494 "macLen": [{
495 "min": 32, "max": 256, "increment": 8
496 }]
497 },
498 {
Adam Langley279740e2019-11-05 11:40:27 -0800499 "algorithm": "ctrDRBG",
500 "revision": "1.0",
501 "predResistanceEnabled": [false],
Adam Langley735a8682022-05-04 16:41:11 -0700502 "reseedImplemented": true,
Adam Langley279740e2019-11-05 11:40:27 -0800503 "capabilities": [{
504 "mode": "AES-256",
505 "derFuncEnabled": false,
506 "entropyInputLen": [384],
507 "nonceLen": [0],
508 "persoStringLen": [{"min": 0, "max": 384, "increment": 16}],
509 "additionalInputLen": [
510 {"min": 0, "max": 384, "increment": 16}
511 ],
512 "returnedBitsLen": 2048
513 }]
Gurleen Grewal913a2402019-11-08 18:09:41 -0800514 },
515 {
516 "algorithm": "ECDSA",
517 "mode": "keyGen",
Adam Langleyb8912d72024-05-14 19:54:45 +0000518 "revision": "FIPS186-5",
Gurleen Grewal913a2402019-11-08 18:09:41 -0800519 "curve": [
520 "P-224",
521 "P-256",
522 "P-384",
523 "P-521"
524 ],
525 "secretGenerationMode": [
526 "testing candidates"
527 ]
528 },
529 {
530 "algorithm": "ECDSA",
531 "mode": "keyVer",
Adam Langleyb8912d72024-05-14 19:54:45 +0000532 "revision": "FIPS186-5",
Gurleen Grewal913a2402019-11-08 18:09:41 -0800533 "curve": [
534 "P-224",
535 "P-256",
536 "P-384",
537 "P-521"
538 ]
539 },
540 {
541 "algorithm": "ECDSA",
542 "mode": "sigGen",
Adam Langleyb8912d72024-05-14 19:54:45 +0000543 "revision": "FIPS186-5",
Gurleen Grewal913a2402019-11-08 18:09:41 -0800544 "capabilities": [{
545 "curve": [
546 "P-224",
547 "P-256",
548 "P-384",
549 "P-521"
550 ],
551 "hashAlg": [
552 "SHA2-224",
553 "SHA2-256",
554 "SHA2-384",
Adam Langley097ffe12022-05-04 15:27:12 -0700555 "SHA2-512",
556 "SHA2-512/256"
Gurleen Grewal913a2402019-11-08 18:09:41 -0800557 ]
558 }]
559 },
560 {
561 "algorithm": "ECDSA",
562 "mode": "sigVer",
Adam Langleyb8912d72024-05-14 19:54:45 +0000563 "revision": "FIPS186-5",
Gurleen Grewal913a2402019-11-08 18:09:41 -0800564 "capabilities": [{
565 "curve": [
566 "P-224",
567 "P-256",
568 "P-384",
569 "P-521"
570 ],
571 "hashAlg": [
572 "SHA2-224",
573 "SHA2-256",
574 "SHA2-384",
Adam Langley097ffe12022-05-04 15:27:12 -0700575 "SHA2-512",
576 "SHA2-512/256"
Gurleen Grewal913a2402019-11-08 18:09:41 -0800577 ]
578 }]
Adam Langleyfb0c05c2020-07-01 13:23:55 -0700579 },
580 {
Adam Langley2e22d1b2020-10-22 07:56:36 -0700581 "algorithm": "RSA",
582 "mode": "keyGen",
Adam Langley43cec432024-03-05 00:40:08 +0000583 "revision": "FIPS186-5",
Adam Langley2e22d1b2020-10-22 07:56:36 -0700584 "infoGeneratedByServer": true,
585 "pubExpMode": "fixed",
586 "fixedPubExp": "010001",
587 "keyFormat": "standard",
588 "capabilities": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000589 "randPQ": "probable",
Adam Langley2e22d1b2020-10-22 07:56:36 -0700590 "properties": [{
591 "modulo": 2048,
592 "primeTest": [
Adam Langleyb8912d72024-05-14 19:54:45 +0000593 "2powSecStr"
Adam Langley2e22d1b2020-10-22 07:56:36 -0700594 ]
595 },{
596 "modulo": 3072,
597 "primeTest": [
Adam Langleyb8912d72024-05-14 19:54:45 +0000598 "2powSecStr"
Adam Langley2e22d1b2020-10-22 07:56:36 -0700599 ]
600 },{
601 "modulo": 4096,
602 "primeTest": [
Adam Langleyb8912d72024-05-14 19:54:45 +0000603 "2powSecStr"
Adam Langley2e22d1b2020-10-22 07:56:36 -0700604 ]
605 }]
606 }]
607 },
608 {
Adam Langleye44d9772020-10-22 16:21:09 -0700609 "algorithm": "RSA",
610 "mode": "sigGen",
Adam Langley43cec432024-03-05 00:40:08 +0000611 "revision": "FIPS186-5",
Adam Langleye44d9772020-10-22 16:21:09 -0700612 "capabilities": [{
613 "sigType": "pkcs1v1.5",
614 "properties": [{
615 "modulo": 2048,
616 "hashPair": [{
617 "hashAlg": "SHA2-224"
618 }, {
619 "hashAlg": "SHA2-256"
620 }, {
621 "hashAlg": "SHA2-384"
622 }, {
623 "hashAlg": "SHA2-512"
Adam Langleye44d9772020-10-22 16:21:09 -0700624 }]
625 }]
626 },{
627 "sigType": "pkcs1v1.5",
628 "properties": [{
629 "modulo": 3072,
630 "hashPair": [{
631 "hashAlg": "SHA2-224"
632 }, {
633 "hashAlg": "SHA2-256"
634 }, {
635 "hashAlg": "SHA2-384"
636 }, {
637 "hashAlg": "SHA2-512"
Adam Langleye44d9772020-10-22 16:21:09 -0700638 }]
639 }]
640 },{
641 "sigType": "pkcs1v1.5",
642 "properties": [{
643 "modulo": 4096,
644 "hashPair": [{
645 "hashAlg": "SHA2-224"
646 }, {
647 "hashAlg": "SHA2-256"
648 }, {
649 "hashAlg": "SHA2-384"
650 }, {
651 "hashAlg": "SHA2-512"
Adam Langleye44d9772020-10-22 16:21:09 -0700652 }]
653 }]
654 },{
655 "sigType": "pss",
656 "properties": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000657 "maskFunction": ["mgf1"],
Adam Langleye44d9772020-10-22 16:21:09 -0700658 "modulo": 2048,
659 "hashPair": [{
660 "hashAlg": "SHA2-224",
661 "saltLen": 28
662 }, {
663 "hashAlg": "SHA2-256",
664 "saltLen": 32
665 }, {
666 "hashAlg": "SHA2-384",
667 "saltLen": 48
668 }, {
669 "hashAlg": "SHA2-512",
670 "saltLen": 64
Adam Langley097ffe12022-05-04 15:27:12 -0700671 }, {
672 "hashAlg": "SHA2-512/256",
673 "saltLen": 32
Adam Langleye44d9772020-10-22 16:21:09 -0700674 }]
675 }]
676 },{
677 "sigType": "pss",
678 "properties": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000679 "maskFunction": ["mgf1"],
Adam Langleye44d9772020-10-22 16:21:09 -0700680 "modulo": 3072,
681 "hashPair": [{
682 "hashAlg": "SHA2-224",
683 "saltLen": 28
684 }, {
685 "hashAlg": "SHA2-256",
686 "saltLen": 32
687 }, {
688 "hashAlg": "SHA2-384",
689 "saltLen": 48
690 }, {
691 "hashAlg": "SHA2-512",
692 "saltLen": 64
Adam Langley097ffe12022-05-04 15:27:12 -0700693 }, {
694 "hashAlg": "SHA2-512/256",
695 "saltLen": 32
Adam Langleye44d9772020-10-22 16:21:09 -0700696 }]
697 }]
698 },{
699 "sigType": "pss",
700 "properties": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000701 "maskFunction": ["mgf1"],
Adam Langleye44d9772020-10-22 16:21:09 -0700702 "modulo": 4096,
703 "hashPair": [{
704 "hashAlg": "SHA2-224",
705 "saltLen": 28
706 }, {
707 "hashAlg": "SHA2-256",
708 "saltLen": 32
709 }, {
710 "hashAlg": "SHA2-384",
711 "saltLen": 48
712 }, {
713 "hashAlg": "SHA2-512",
714 "saltLen": 64
Adam Langley097ffe12022-05-04 15:27:12 -0700715 }, {
716 "hashAlg": "SHA2-512/256",
717 "saltLen": 32
Adam Langleye44d9772020-10-22 16:21:09 -0700718 }]
719 }]
720 }]
721 },
722 {
Adam Langley777e1ff2020-10-22 16:57:56 -0700723 "algorithm": "RSA",
724 "mode": "sigVer",
Adam Langley43cec432024-03-05 00:40:08 +0000725 "revision": "FIPS186-5",
Adam Langley777e1ff2020-10-22 16:57:56 -0700726 "pubExpMode": "fixed",
727 "fixedPubExp": "010001",
728 "capabilities": [{
729 "sigType": "pkcs1v1.5",
730 "properties": [{
Adam Langley777e1ff2020-10-22 16:57:56 -0700731 "modulo": 2048,
732 "hashPair": [{
733 "hashAlg": "SHA2-224"
734 }, {
735 "hashAlg": "SHA2-256"
736 }, {
737 "hashAlg": "SHA2-384"
738 }, {
739 "hashAlg": "SHA2-512"
Adam Langley777e1ff2020-10-22 16:57:56 -0700740 }]
741 }]
742 },{
743 "sigType": "pkcs1v1.5",
744 "properties": [{
745 "modulo": 3072,
746 "hashPair": [{
747 "hashAlg": "SHA2-224"
748 }, {
749 "hashAlg": "SHA2-256"
750 }, {
751 "hashAlg": "SHA2-384"
752 }, {
753 "hashAlg": "SHA2-512"
Adam Langley777e1ff2020-10-22 16:57:56 -0700754 }]
755 }]
756 },{
757 "sigType": "pkcs1v1.5",
758 "properties": [{
759 "modulo": 4096,
760 "hashPair": [{
761 "hashAlg": "SHA2-224"
762 }, {
763 "hashAlg": "SHA2-256"
764 }, {
765 "hashAlg": "SHA2-384"
766 }, {
767 "hashAlg": "SHA2-512"
Adam Langley1a541d42022-05-04 14:42:30 -0700768 }]
769 }]
770 },{
771 "sigType": "pss",
772 "properties": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000773 "maskFunction": ["mgf1"],
Adam Langley777e1ff2020-10-22 16:57:56 -0700774 "modulo": 2048,
775 "hashPair": [{
776 "hashAlg": "SHA2-224",
777 "saltLen": 28
778 }, {
779 "hashAlg": "SHA2-256",
780 "saltLen": 32
781 }, {
782 "hashAlg": "SHA2-384",
783 "saltLen": 48
784 }, {
785 "hashAlg": "SHA2-512",
786 "saltLen": 64
787 }, {
Adam Langley097ffe12022-05-04 15:27:12 -0700788 "hashAlg": "SHA2-512/256",
789 "saltLen": 32
Adam Langley777e1ff2020-10-22 16:57:56 -0700790 }]
791 }]
792 },{
793 "sigType": "pss",
794 "properties": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000795 "maskFunction": ["mgf1"],
Adam Langley777e1ff2020-10-22 16:57:56 -0700796 "modulo": 3072,
797 "hashPair": [{
798 "hashAlg": "SHA2-224",
799 "saltLen": 28
800 }, {
801 "hashAlg": "SHA2-256",
802 "saltLen": 32
803 }, {
804 "hashAlg": "SHA2-384",
805 "saltLen": 48
806 }, {
807 "hashAlg": "SHA2-512",
808 "saltLen": 64
809 }, {
Adam Langley097ffe12022-05-04 15:27:12 -0700810 "hashAlg": "SHA2-512/256",
811 "saltLen": 32
Adam Langley777e1ff2020-10-22 16:57:56 -0700812 }]
813 }]
814 },{
815 "sigType": "pss",
816 "properties": [{
Adam Langleyb8912d72024-05-14 19:54:45 +0000817 "maskFunction": ["mgf1"],
Adam Langley777e1ff2020-10-22 16:57:56 -0700818 "modulo": 4096,
819 "hashPair": [{
820 "hashAlg": "SHA2-224",
821 "saltLen": 28
822 }, {
823 "hashAlg": "SHA2-256",
824 "saltLen": 32
825 }, {
826 "hashAlg": "SHA2-384",
827 "saltLen": 48
828 }, {
829 "hashAlg": "SHA2-512",
830 "saltLen": 64
831 }, {
Adam Langley097ffe12022-05-04 15:27:12 -0700832 "hashAlg": "SHA2-512/256",
833 "saltLen": 32
Adam Langley777e1ff2020-10-22 16:57:56 -0700834 }]
835 }]
836 }]
837 },
838 {
Adam Langleyfb0c05c2020-07-01 13:23:55 -0700839 "algorithm": "CMAC-AES",
Adam Langleyfc233002021-02-09 13:39:28 -0800840 "acvptoolTestOnly": true,
Adam Langleyfb0c05c2020-07-01 13:23:55 -0700841 "revision": "1.0",
842 "capabilities": [{
Adam Langley4d3e5402021-02-09 13:30:05 -0800843 "direction": ["gen", "ver"],
Adam Langleyfb0c05c2020-07-01 13:23:55 -0700844 "msgLen": [{
845 "min": 0,
Adam Langley828b2d22022-05-30 16:36:40 -0700846 "max": 524288,
Adam Langleyfb0c05c2020-07-01 13:23:55 -0700847 "increment": 8
848 }],
849 "keyLen": [128, 256],
850 "macLen": [{
Adam Langley828b2d22022-05-30 16:36:40 -0700851 "min": 8,
Adam Langleyfb0c05c2020-07-01 13:23:55 -0700852 "max": 128,
853 "increment": 8
854 }]
855 }]
Adam Langleyf0400012020-12-07 15:06:13 -0800856 },
857 {
Adam Langley0898b072020-12-08 13:44:02 -0800858 "algorithm": "KAS-ECC-SSC",
859 "revision": "Sp800-56Ar3",
860 "scheme": {
861 "ephemeralUnified": {
862 "kasRole": [
863 "initiator",
864 "responder"
865 ]
Adam Langley09f71c12021-04-08 15:34:13 -0700866 },
867 "staticUnified": {
868 "kasRole": [
869 "initiator",
870 "responder"
871 ]
Adam Langley0898b072020-12-08 13:44:02 -0800872 }
873 },
874 "domainParameterGenerationMethods": [
875 "P-224",
876 "P-256",
877 "P-384",
878 "P-521"
879 ]
Adam Langley28cab642020-12-10 06:59:26 -0800880 },
881 {
Adam Langleyd09962d2021-01-25 11:28:08 -0800882 "algorithm": "KAS-FFC-SSC",
883 "revision": "Sp800-56Ar3",
Adam Langley28cab642020-12-10 06:59:26 -0800884 "scheme": {
885 "dhEphem": {
886 "kasRole": [
887 "initiator"
Adam Langleyd09962d2021-01-25 11:28:08 -0800888 ]
Adam Langley28cab642020-12-10 06:59:26 -0800889 }
Adam Langleyd09962d2021-01-25 11:28:08 -0800890 },
891 "domainParameterGenerationMethods": [
892 "FB",
893 "FC"
894 ]
Adam Langleyd3acd452023-04-12 23:03:11 +0000895 },
896 {
897 "algorithm": "KDA",
898 "mode": "HKDF",
899 "revision": "Sp800-56Cr1",
900 "fixedInfoPattern": "uPartyInfo||vPartyInfo",
901 "encoding": [
902 "concatenation"
903 ],
904 "hmacAlg": [
905 "SHA2-224",
906 "SHA2-256",
907 "SHA2-384",
908 "SHA2-512",
909 "SHA2-512/256"
910 ],
911 "macSaltMethods": [
912 "default",
913 "random"
914 ],
915 "l": 2048,
916 "z": [
917 {
918 "min": 224,
919 "max": 65336,
920 "increment": 8
921 }
922 ]
Adam Langley480344d2023-04-13 02:09:12 +0000923 },
924 {
Adam Langley6e1e3672023-04-15 00:04:12 +0000925 "algorithm": "TLS-v1.2",
926 "mode": "KDF",
927 "revision": "RFC7627",
928 "hashAlg": [
929 "SHA2-256",
930 "SHA2-384",
931 "SHA2-512"
932 ]
933 },
934 {
Adam Langley480344d2023-04-13 02:09:12 +0000935 "algorithm": "TLS-v1.3",
936 "mode": "KDF",
937 "revision": "RFC8446",
938 "hmacAlg": [
939 "SHA2-256",
940 "SHA2-384"
941 ],
942 "runningMode": [
943 "DHE",
944 "PSK",
945 "PSK-DHE"
946 ]
Adam Langley830e7862024-11-21 16:32:38 -0800947 },
948 {
949 "algorithm": "ML-DSA",
950 "mode": "keyGen",
951 "revision": "FIPS204",
952 "parameterSets": [
953 "ML-DSA-65",
954 "ML-DSA-87"
955 ]
956 },
957 {
958 "algorithm": "ML-DSA",
959 "mode": "sigGen",
960 "revision": "FIPS204",
961 "parameterSets": [
962 "ML-DSA-65",
963 "ML-DSA-87"
964 ],
965 "deterministic": [
966 true,
967 false
968 ],
969 "messageLength": [
970 {
971 "min": 8,
972 "max": 65536,
973 "increment": 8
974 }
975 ]
976 },
977 {
978 "algorithm": "ML-DSA",
979 "mode": "sigVer",
980 "revision": "FIPS204",
981 "parameterSets": [
982 "ML-DSA-65",
983 "ML-DSA-87"
984 ]
Adam Langley279740e2019-11-05 11:40:27 -0800985 }
Gurleen Grewal913a2402019-11-08 18:09:41 -0800986 ])";
Stephen Cranebc0a4f12021-02-12 15:12:29 -0800987 return write_reply({Span<const uint8_t>(
988 reinterpret_cast<const uint8_t *>(kConfig), sizeof(kConfig) - 1)});
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700989}
990
Adam Langleye24491a2022-11-25 21:23:03 +0000991static bool Flush(const Span<const uint8_t> args[], ReplyCallback write_reply) {
992 fprintf(
993 stderr,
994 "modulewrapper code processed a `flush` command but this must be handled "
995 "at a higher-level. See the example in main.cc in BoringSSL\n");
996 abort();
997}
998
Adam Langleyb7f0c1b2019-07-09 18:02:14 -0700999template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),
1000 size_t DigestLength>
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001001static bool Hash(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07001002 uint8_t digest[DigestLength];
1003 OneShotHash(args[0].data(), args[0].size(), digest);
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001004 return write_reply({Span<const uint8_t>(digest)});
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07001005}
1006
Adam Langley9fc61742021-05-06 12:15:07 -07001007template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),
1008 size_t DigestLength>
1009static bool HashMCT(const Span<const uint8_t> args[],
1010 ReplyCallback write_reply) {
1011 if (args[0].size() != DigestLength) {
1012 return false;
1013 }
1014
1015 uint8_t buf[DigestLength * 3];
1016 memcpy(buf, args[0].data(), DigestLength);
1017 memcpy(buf + DigestLength, args[0].data(), DigestLength);
1018 memcpy(buf + 2 * DigestLength, args[0].data(), DigestLength);
1019
1020 for (size_t i = 0; i < 1000; i++) {
1021 uint8_t digest[DigestLength];
1022 OneShotHash(buf, sizeof(buf), digest);
1023 memmove(buf, buf + DigestLength, DigestLength * 2);
1024 memcpy(buf + DigestLength * 2, digest, DigestLength);
1025 }
1026
1027 return write_reply(
1028 {Span<const uint8_t>(buf + 2 * DigestLength, DigestLength)});
1029}
1030
Adam Langley1607f542020-11-03 15:34:57 -08001031static uint32_t GetIterations(const Span<const uint8_t> iterations_bytes) {
1032 uint32_t iterations;
1033 if (iterations_bytes.size() != sizeof(iterations)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001034 LOG_ERROR(
1035 "Expected %u-byte input for number of iterations, but found %u "
1036 "bytes.\n",
1037 static_cast<unsigned>(sizeof(iterations)),
1038 static_cast<unsigned>(iterations_bytes.size()));
Adam Langley1607f542020-11-03 15:34:57 -08001039 abort();
1040 }
1041
1042 memcpy(&iterations, iterations_bytes.data(), sizeof(iterations));
1043 if (iterations == 0 || iterations == UINT32_MAX) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001044 LOG_ERROR("Invalid number of iterations: %x.\n",
Adam Langley830e7862024-11-21 16:32:38 -08001045 static_cast<unsigned>(iterations));
Adam Langley1607f542020-11-03 15:34:57 -08001046 abort();
1047 }
1048
1049 return iterations;
1050}
1051
Adam Langley974f4dd2019-08-01 17:20:31 -07001052template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
1053 void (*Block)(const uint8_t *in, uint8_t *out, const AES_KEY *key)>
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001054static bool AES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Adam Langley974f4dd2019-08-01 17:20:31 -07001055 AES_KEY key;
1056 if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
1057 return false;
1058 }
1059 if (args[1].size() % AES_BLOCK_SIZE != 0) {
1060 return false;
1061 }
Adam Langley1607f542020-11-03 15:34:57 -08001062 std::vector<uint8_t> result(args[1].begin(), args[1].end());
1063 const uint32_t iterations = GetIterations(args[2]);
Adam Langley974f4dd2019-08-01 17:20:31 -07001064
Adam Langley1607f542020-11-03 15:34:57 -08001065 std::vector<uint8_t> prev_result;
1066 for (uint32_t j = 0; j < iterations; j++) {
1067 if (j == iterations - 1) {
1068 prev_result = result;
1069 }
1070
1071 for (size_t i = 0; i < args[1].size(); i += AES_BLOCK_SIZE) {
1072 Block(result.data() + i, result.data() + i, &key);
1073 }
Adam Langley974f4dd2019-08-01 17:20:31 -07001074 }
Adam Langley1607f542020-11-03 15:34:57 -08001075
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001076 return write_reply(
1077 {Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
Adam Langley974f4dd2019-08-01 17:20:31 -07001078}
1079
1080template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
1081 int Direction>
Adam Langley830e7862024-11-21 16:32:38 -08001082static bool AES_CBC(const Span<const uint8_t> args[],
1083 ReplyCallback write_reply) {
Adam Langley974f4dd2019-08-01 17:20:31 -07001084 AES_KEY key;
1085 if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
1086 return false;
1087 }
Adam Langley1607f542020-11-03 15:34:57 -08001088 if (args[1].size() % AES_BLOCK_SIZE != 0 || args[1].empty() ||
Adam Langley974f4dd2019-08-01 17:20:31 -07001089 args[2].size() != AES_BLOCK_SIZE) {
1090 return false;
1091 }
Adam Langley1607f542020-11-03 15:34:57 -08001092 std::vector<uint8_t> input(args[1].begin(), args[1].end());
1093 std::vector<uint8_t> iv(args[2].begin(), args[2].end());
1094 const uint32_t iterations = GetIterations(args[3]);
Adam Langley974f4dd2019-08-01 17:20:31 -07001095
Adam Langley1607f542020-11-03 15:34:57 -08001096 std::vector<uint8_t> result(input.size());
1097 std::vector<uint8_t> prev_result, prev_input;
1098
1099 for (uint32_t j = 0; j < iterations; j++) {
1100 prev_result = result;
1101 if (j > 0) {
1102 if (Direction == AES_ENCRYPT) {
1103 iv = result;
1104 } else {
1105 iv = prev_input;
1106 }
1107 }
1108
1109 // AES_cbc_encrypt will mutate the given IV, but we need it later.
1110 uint8_t iv_copy[AES_BLOCK_SIZE];
1111 memcpy(iv_copy, iv.data(), sizeof(iv_copy));
1112 AES_cbc_encrypt(input.data(), result.data(), input.size(), &key, iv_copy,
1113 Direction);
1114
1115 if (Direction == AES_DECRYPT) {
1116 prev_input = input;
1117 }
1118
1119 if (j == 0) {
1120 input = iv;
1121 } else {
1122 input = prev_result;
1123 }
1124 }
1125
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001126 return write_reply(
1127 {Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
Adam Langley974f4dd2019-08-01 17:20:31 -07001128}
1129
Adam Langley830e7862024-11-21 16:32:38 -08001130static bool AES_CTR(const Span<const uint8_t> args[],
1131 ReplyCallback write_reply) {
Adam Langley4ab14ea2020-12-17 14:03:23 -08001132 static const uint32_t kOneIteration = 1;
1133 if (args[3].size() != sizeof(kOneIteration) ||
1134 memcmp(args[3].data(), &kOneIteration, sizeof(kOneIteration))) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001135 LOG_ERROR("Only a single iteration supported with AES-CTR\n");
Adam Langley4ab14ea2020-12-17 14:03:23 -08001136 return false;
1137 }
1138
Adam Langley67818be2020-09-29 10:59:35 -07001139 AES_KEY key;
1140 if (AES_set_encrypt_key(args[0].data(), args[0].size() * 8, &key) != 0) {
1141 return false;
1142 }
1143 if (args[2].size() != AES_BLOCK_SIZE) {
1144 return false;
1145 }
1146 uint8_t iv[AES_BLOCK_SIZE];
1147 memcpy(iv, args[2].data(), AES_BLOCK_SIZE);
Adam Langley1607f542020-11-03 15:34:57 -08001148 if (GetIterations(args[3]) != 1) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001149 LOG_ERROR("Multiple iterations of AES-CTR is not supported.\n");
Adam Langley1607f542020-11-03 15:34:57 -08001150 return false;
1151 }
Adam Langley67818be2020-09-29 10:59:35 -07001152
1153 std::vector<uint8_t> out;
1154 out.resize(args[1].size());
1155 unsigned num = 0;
1156 uint8_t ecount_buf[AES_BLOCK_SIZE];
1157 AES_ctr128_encrypt(args[1].data(), out.data(), args[1].size(), &key, iv,
1158 ecount_buf, &num);
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001159 return write_reply({Span<const uint8_t>(out)});
Adam Langley67818be2020-09-29 10:59:35 -07001160}
1161
Adam Langleyfda92cd2020-09-29 11:00:51 -07001162static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
1163 Span<const uint8_t> key) {
Adam Langley8f4e9d42024-01-11 18:03:59 +00001164 if (tag_len_span.size() != sizeof(uint32_t)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001165 LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
1166 static_cast<unsigned>(tag_len_span.size()));
Adam Langleyfda92cd2020-09-29 11:00:51 -07001167 return false;
1168 }
Adam Langley8f4e9d42024-01-11 18:03:59 +00001169 const uint32_t tag_len_32 = CRYPTO_load_u32_le(tag_len_span.data());
Adam Langleyfda92cd2020-09-29 11:00:51 -07001170
1171 const EVP_AEAD *aead;
1172 switch (key.size()) {
1173 case 16:
1174 aead = EVP_aead_aes_128_gcm();
1175 break;
1176 case 24:
1177 aead = EVP_aead_aes_192_gcm();
1178 break;
1179 case 32:
1180 aead = EVP_aead_aes_256_gcm();
1181 break;
1182 default:
Adam Langley8f4e9d42024-01-11 18:03:59 +00001183 LOG_ERROR("Bad AES-GCM key length %u\n",
1184 static_cast<unsigned>(key.size()));
Adam Langleyfda92cd2020-09-29 11:00:51 -07001185 return false;
1186 }
1187
1188 if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(), tag_len_32,
1189 nullptr)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001190 LOG_ERROR("Failed to setup AES-GCM with tag length %u\n",
1191 static_cast<unsigned>(tag_len_32));
Adam Langleyfda92cd2020-09-29 11:00:51 -07001192 return false;
1193 }
1194
1195 return true;
1196}
1197
Adam Langley8f4e9d42024-01-11 18:03:59 +00001198static bool AESGCMRandNonceSetup(EVP_AEAD_CTX *ctx,
1199 Span<const uint8_t> tag_len_span,
1200 Span<const uint8_t> key) {
1201 if (tag_len_span.size() != sizeof(uint32_t)) {
1202 LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
1203 static_cast<unsigned>(tag_len_span.size()));
1204 return false;
1205 }
1206 const uint32_t tag_len_32 = CRYPTO_load_u32_le(tag_len_span.data());
1207
1208 const EVP_AEAD *aead;
1209 switch (key.size()) {
1210 case 16:
1211 aead = EVP_aead_aes_128_gcm_randnonce();
1212 break;
1213 case 32:
1214 aead = EVP_aead_aes_256_gcm_randnonce();
1215 break;
1216 default:
1217 LOG_ERROR("Bad AES-GCM key length %u\n",
1218 static_cast<unsigned>(key.size()));
1219 return false;
1220 }
1221
1222 constexpr size_t kNonceLength = 12;
1223 if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(),
1224 tag_len_32 + kNonceLength, nullptr)) {
1225 LOG_ERROR("Failed to setup AES-GCM with tag length %u\n",
1226 static_cast<unsigned>(tag_len_32));
1227 return false;
1228 }
1229
1230 return true;
1231}
1232
Adam Langleyf94e6d72020-10-02 14:04:37 -07001233static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
1234 Span<const uint8_t> key) {
1235 uint32_t tag_len_32;
1236 if (tag_len_span.size() != sizeof(tag_len_32)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001237 LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
1238 static_cast<unsigned>(tag_len_span.size()));
Adam Langleyf94e6d72020-10-02 14:04:37 -07001239 return false;
1240 }
1241 memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32));
Adam Langley828b2d22022-05-30 16:36:40 -07001242 const EVP_AEAD *aead;
1243 switch (tag_len_32) {
1244 case 4:
1245 aead = EVP_aead_aes_128_ccm_bluetooth();
1246 break;
1247
1248 case 8:
1249 aead = EVP_aead_aes_128_ccm_bluetooth_8();
1250 break;
1251
1252 default:
1253 LOG_ERROR(
1254 "AES-CCM only supports 4- and 8-byte tags, but %u was requested\n",
1255 static_cast<unsigned>(tag_len_32));
1256 return false;
Adam Langleyf94e6d72020-10-02 14:04:37 -07001257 }
1258
1259 if (key.size() != 16) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001260 LOG_ERROR("AES-CCM only supports 128-bit keys, but %u bits were given\n",
1261 static_cast<unsigned>(key.size() * 8));
Adam Langleyf94e6d72020-10-02 14:04:37 -07001262 return false;
1263 }
1264
Adam Langley828b2d22022-05-30 16:36:40 -07001265 if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(), tag_len_32,
1266 nullptr)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001267 LOG_ERROR("Failed to setup AES-CCM with tag length %u\n",
1268 static_cast<unsigned>(tag_len_32));
Adam Langleyf94e6d72020-10-02 14:04:37 -07001269 return false;
1270 }
1271
1272 return true;
1273}
1274
1275template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
1276 Span<const uint8_t> key)>
Adam Langley830e7862024-11-21 16:32:38 -08001277static bool AEADSeal(const Span<const uint8_t> args[],
1278 ReplyCallback write_reply) {
Adam Langleyfda92cd2020-09-29 11:00:51 -07001279 Span<const uint8_t> tag_len_span = args[0];
1280 Span<const uint8_t> key = args[1];
1281 Span<const uint8_t> plaintext = args[2];
1282 Span<const uint8_t> nonce = args[3];
1283 Span<const uint8_t> ad = args[4];
1284
1285 bssl::ScopedEVP_AEAD_CTX ctx;
Adam Langleyf94e6d72020-10-02 14:04:37 -07001286 if (!SetupFunc(ctx.get(), tag_len_span, key)) {
Adam Langleyfda92cd2020-09-29 11:00:51 -07001287 return false;
1288 }
1289
1290 if (EVP_AEAD_MAX_OVERHEAD + plaintext.size() < EVP_AEAD_MAX_OVERHEAD) {
1291 return false;
1292 }
1293 std::vector<uint8_t> out(EVP_AEAD_MAX_OVERHEAD + plaintext.size());
1294
1295 size_t out_len;
1296 if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
1297 nonce.data(), nonce.size(), plaintext.data(),
1298 plaintext.size(), ad.data(), ad.size())) {
1299 return false;
1300 }
1301
1302 out.resize(out_len);
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001303 return write_reply({Span<const uint8_t>(out)});
Adam Langleyfda92cd2020-09-29 11:00:51 -07001304}
1305
Adam Langleyf94e6d72020-10-02 14:04:37 -07001306template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
1307 Span<const uint8_t> key)>
Adam Langley830e7862024-11-21 16:32:38 -08001308static bool AEADOpen(const Span<const uint8_t> args[],
1309 ReplyCallback write_reply) {
Adam Langleyfda92cd2020-09-29 11:00:51 -07001310 Span<const uint8_t> tag_len_span = args[0];
1311 Span<const uint8_t> key = args[1];
1312 Span<const uint8_t> ciphertext = args[2];
1313 Span<const uint8_t> nonce = args[3];
1314 Span<const uint8_t> ad = args[4];
1315
1316 bssl::ScopedEVP_AEAD_CTX ctx;
Adam Langleyf94e6d72020-10-02 14:04:37 -07001317 if (!SetupFunc(ctx.get(), tag_len_span, key)) {
Adam Langleyfda92cd2020-09-29 11:00:51 -07001318 return false;
1319 }
1320
1321 std::vector<uint8_t> out(ciphertext.size());
1322 size_t out_len;
Adam Langley81658a92020-09-29 14:54:09 -07001323 uint8_t success_flag[1] = {0};
Adam Langleyfda92cd2020-09-29 11:00:51 -07001324
1325 if (!EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
1326 nonce.data(), nonce.size(), ciphertext.data(),
1327 ciphertext.size(), ad.data(), ad.size())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001328 return write_reply(
1329 {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
Adam Langleyfda92cd2020-09-29 11:00:51 -07001330 }
1331
1332 out.resize(out_len);
Adam Langley81658a92020-09-29 14:54:09 -07001333 success_flag[0] = 1;
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001334 return write_reply(
1335 {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
Adam Langley81658a92020-09-29 14:54:09 -07001336}
1337
Adam Langleyb117a3a2020-09-29 15:36:52 -07001338static bool AESPaddedKeyWrapSetup(AES_KEY *out, bool decrypt,
1339 Span<const uint8_t> key) {
Adam Langley81658a92020-09-29 14:54:09 -07001340 if ((decrypt ? AES_set_decrypt_key : AES_set_encrypt_key)(
1341 key.data(), key.size() * 8, out) != 0) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001342 LOG_ERROR("Invalid AES key length for AES-KW(P): %u\n",
1343 static_cast<unsigned>(key.size()));
Adam Langley81658a92020-09-29 14:54:09 -07001344 return false;
1345 }
Adam Langleyb117a3a2020-09-29 15:36:52 -07001346 return true;
1347}
1348
1349static bool AESKeyWrapSetup(AES_KEY *out, bool decrypt, Span<const uint8_t> key,
1350 Span<const uint8_t> input) {
1351 if (!AESPaddedKeyWrapSetup(out, decrypt, key)) {
1352 return false;
1353 }
1354
Adam Langley81658a92020-09-29 14:54:09 -07001355 if (input.size() % 8) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001356 LOG_ERROR("Invalid AES-KW input length: %u\n",
1357 static_cast<unsigned>(input.size()));
Adam Langley81658a92020-09-29 14:54:09 -07001358 return false;
1359 }
1360
1361 return true;
1362}
1363
Adam Langley830e7862024-11-21 16:32:38 -08001364static bool AESKeyWrapSeal(const Span<const uint8_t> args[],
1365 ReplyCallback write_reply) {
Adam Langley81658a92020-09-29 14:54:09 -07001366 Span<const uint8_t> key = args[1];
1367 Span<const uint8_t> plaintext = args[2];
1368
1369 AES_KEY aes;
1370 if (!AESKeyWrapSetup(&aes, /*decrypt=*/false, key, plaintext) ||
1371 plaintext.size() > INT_MAX - 8) {
1372 return false;
1373 }
1374
1375 std::vector<uint8_t> out(plaintext.size() + 8);
1376 if (AES_wrap_key(&aes, /*iv=*/nullptr, out.data(), plaintext.data(),
1377 plaintext.size()) != static_cast<int>(out.size())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001378 LOG_ERROR("AES-KW failed\n");
Adam Langley81658a92020-09-29 14:54:09 -07001379 return false;
1380 }
1381
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001382 return write_reply({Span<const uint8_t>(out)});
Adam Langley81658a92020-09-29 14:54:09 -07001383}
1384
Adam Langley830e7862024-11-21 16:32:38 -08001385static bool AESKeyWrapOpen(const Span<const uint8_t> args[],
1386 ReplyCallback write_reply) {
Adam Langley81658a92020-09-29 14:54:09 -07001387 Span<const uint8_t> key = args[1];
1388 Span<const uint8_t> ciphertext = args[2];
1389
1390 AES_KEY aes;
1391 if (!AESKeyWrapSetup(&aes, /*decrypt=*/true, key, ciphertext) ||
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001392 ciphertext.size() < 8 || ciphertext.size() > INT_MAX) {
Adam Langley81658a92020-09-29 14:54:09 -07001393 return false;
1394 }
1395
1396 std::vector<uint8_t> out(ciphertext.size() - 8);
1397 uint8_t success_flag[1] = {0};
1398 if (AES_unwrap_key(&aes, /*iv=*/nullptr, out.data(), ciphertext.data(),
1399 ciphertext.size()) != static_cast<int>(out.size())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001400 return write_reply(
1401 {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
Adam Langley81658a92020-09-29 14:54:09 -07001402 }
1403
1404 success_flag[0] = 1;
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001405 return write_reply(
1406 {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
Adam Langleyfda92cd2020-09-29 11:00:51 -07001407}
1408
Adam Langley830e7862024-11-21 16:32:38 -08001409static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[],
1410 ReplyCallback write_reply) {
Adam Langleyb117a3a2020-09-29 15:36:52 -07001411 Span<const uint8_t> key = args[1];
1412 Span<const uint8_t> plaintext = args[2];
1413
1414 AES_KEY aes;
1415 if (!AESPaddedKeyWrapSetup(&aes, /*decrypt=*/false, key) ||
1416 plaintext.size() + 15 < 15) {
1417 return false;
1418 }
1419
1420 std::vector<uint8_t> out(plaintext.size() + 15);
1421 size_t out_len;
1422 if (!AES_wrap_key_padded(&aes, out.data(), &out_len, out.size(),
1423 plaintext.data(), plaintext.size())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001424 LOG_ERROR("AES-KWP failed\n");
Adam Langleyb117a3a2020-09-29 15:36:52 -07001425 return false;
1426 }
1427
1428 out.resize(out_len);
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001429 return write_reply({Span<const uint8_t>(out)});
Adam Langleyb117a3a2020-09-29 15:36:52 -07001430}
1431
Adam Langley830e7862024-11-21 16:32:38 -08001432static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[],
1433 ReplyCallback write_reply) {
Adam Langleyb117a3a2020-09-29 15:36:52 -07001434 Span<const uint8_t> key = args[1];
1435 Span<const uint8_t> ciphertext = args[2];
1436
1437 AES_KEY aes;
1438 if (!AESPaddedKeyWrapSetup(&aes, /*decrypt=*/true, key) ||
1439 ciphertext.size() % 8) {
1440 return false;
1441 }
1442
1443 std::vector<uint8_t> out(ciphertext.size());
1444 size_t out_len;
1445 uint8_t success_flag[1] = {0};
1446 if (!AES_unwrap_key_padded(&aes, out.data(), &out_len, out.size(),
1447 ciphertext.data(), ciphertext.size())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001448 return write_reply(
1449 {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
Adam Langleyb117a3a2020-09-29 15:36:52 -07001450 }
1451
1452 success_flag[0] = 1;
1453 out.resize(out_len);
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001454 return write_reply(
1455 {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
Adam Langleyb117a3a2020-09-29 15:36:52 -07001456}
1457
Adam Langley1607f542020-11-03 15:34:57 -08001458template <bool Encrypt>
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001459static bool TDES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Adam Langley1607f542020-11-03 15:34:57 -08001460 const EVP_CIPHER *cipher = EVP_des_ede3();
Adam Langleye796cc62020-10-07 14:48:48 -07001461
1462 if (args[0].size() != 24) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001463 LOG_ERROR("Bad key length %u for 3DES.\n",
1464 static_cast<unsigned>(args[0].size()));
Adam Langleye796cc62020-10-07 14:48:48 -07001465 return false;
1466 }
Adam Langley1607f542020-11-03 15:34:57 -08001467 bssl::ScopedEVP_CIPHER_CTX ctx;
1468 if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, args[0].data(), nullptr,
1469 Encrypt ? 1 : 0) ||
1470 !EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) {
1471 return false;
1472 }
1473
Adam Langleye796cc62020-10-07 14:48:48 -07001474 if (args[1].size() % 8) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001475 LOG_ERROR("Bad input length %u for 3DES.\n",
1476 static_cast<unsigned>(args[1].size()));
Adam Langleye796cc62020-10-07 14:48:48 -07001477 return false;
1478 }
Adam Langley1607f542020-11-03 15:34:57 -08001479 std::vector<uint8_t> result(args[1].begin(), args[1].end());
1480
1481 const uint32_t iterations = GetIterations(args[2]);
1482 std::vector<uint8_t> prev_result, prev_prev_result;
1483
1484 for (uint32_t j = 0; j < iterations; j++) {
1485 if (j == iterations - 1) {
1486 prev_result = result;
1487 } else if (iterations >= 2 && j == iterations - 2) {
1488 prev_prev_result = result;
1489 }
1490
1491 int out_len;
1492 if (!EVP_CipherUpdate(ctx.get(), result.data(), &out_len, result.data(),
1493 result.size()) ||
1494 out_len != static_cast<int>(result.size())) {
1495 return false;
1496 }
1497 }
1498
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001499 return write_reply({Span<const uint8_t>(result),
1500 Span<const uint8_t>(prev_result),
1501 Span<const uint8_t>(prev_prev_result)});
Adam Langley1607f542020-11-03 15:34:57 -08001502}
1503
1504template <bool Encrypt>
Adam Langley830e7862024-11-21 16:32:38 -08001505static bool TDES_CBC(const Span<const uint8_t> args[],
1506 ReplyCallback write_reply) {
Adam Langley1607f542020-11-03 15:34:57 -08001507 const EVP_CIPHER *cipher = EVP_des_ede3_cbc();
1508
1509 if (args[0].size() != 24) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001510 LOG_ERROR("Bad key length %u for 3DES.\n",
1511 static_cast<unsigned>(args[0].size()));
Adam Langley1607f542020-11-03 15:34:57 -08001512 return false;
1513 }
1514
1515 if (args[1].size() % 8 || args[1].size() == 0) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001516 LOG_ERROR("Bad input length %u for 3DES.\n",
1517 static_cast<unsigned>(args[1].size()));
Adam Langley1607f542020-11-03 15:34:57 -08001518 return false;
1519 }
1520 std::vector<uint8_t> input(args[1].begin(), args[1].end());
1521
1522 if (args[2].size() != EVP_CIPHER_iv_length(cipher)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001523 LOG_ERROR("Bad IV length %u for 3DES.\n",
1524 static_cast<unsigned>(args[2].size()));
Adam Langley9c12f012020-10-07 16:58:25 -07001525 return false;
1526 }
Adam Langley1607f542020-11-03 15:34:57 -08001527 std::vector<uint8_t> iv(args[2].begin(), args[2].end());
1528 const uint32_t iterations = GetIterations(args[3]);
Adam Langleye796cc62020-10-07 14:48:48 -07001529
Adam Langley1607f542020-11-03 15:34:57 -08001530 std::vector<uint8_t> result(input.size());
1531 std::vector<uint8_t> prev_result, prev_prev_result;
Adam Langleye796cc62020-10-07 14:48:48 -07001532 bssl::ScopedEVP_CIPHER_CTX ctx;
Adam Langley1607f542020-11-03 15:34:57 -08001533 if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, args[0].data(), iv.data(),
1534 Encrypt ? 1 : 0) ||
1535 !EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) {
Adam Langleye796cc62020-10-07 14:48:48 -07001536 return false;
1537 }
1538
Adam Langley1607f542020-11-03 15:34:57 -08001539 for (uint32_t j = 0; j < iterations; j++) {
1540 prev_prev_result = prev_result;
1541 prev_result = result;
1542
1543 int out_len, out_len2;
1544 if (!EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, nullptr, iv.data(),
1545 -1) ||
1546 !EVP_CipherUpdate(ctx.get(), result.data(), &out_len, input.data(),
1547 input.size()) ||
1548 !EVP_CipherFinal_ex(ctx.get(), result.data() + out_len, &out_len2) ||
1549 (out_len + out_len2) != static_cast<int>(result.size())) {
1550 return false;
1551 }
1552
1553 if (Encrypt) {
1554 if (j == 0) {
1555 input = iv;
1556 } else {
1557 input = prev_result;
1558 }
1559 iv = result;
1560 } else {
1561 iv = input;
1562 input = result;
1563 }
1564 }
1565
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001566 return write_reply({Span<const uint8_t>(result),
Adam Langley830e7862024-11-21 16:32:38 -08001567 Span<const uint8_t>(prev_result),
1568 Span<const uint8_t>(prev_prev_result)});
Adam Langleye796cc62020-10-07 14:48:48 -07001569}
1570
Gurleen Grewal2085c7c2019-10-25 13:20:17 -07001571template <const EVP_MD *HashFunc()>
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001572static bool HMAC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Gurleen Grewal2085c7c2019-10-25 13:20:17 -07001573 const EVP_MD *const md = HashFunc();
1574 uint8_t digest[EVP_MAX_MD_SIZE];
1575 unsigned digest_len;
1576 if (::HMAC(md, args[1].data(), args[1].size(), args[0].data(), args[0].size(),
1577 digest, &digest_len) == nullptr) {
1578 return false;
1579 }
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001580 return write_reply({Span<const uint8_t>(digest, digest_len)});
Gurleen Grewal2085c7c2019-10-25 13:20:17 -07001581}
1582
Adam Langleyd3acd452023-04-12 23:03:11 +00001583template <const EVP_MD *HashFunc()>
1584static bool HKDF(const Span<const uint8_t> args[], ReplyCallback write_reply) {
1585 const EVP_MD *const md = HashFunc();
1586 const auto key = args[0];
1587 const auto salt = args[1];
1588 const auto info = args[2];
1589 const auto out_len_bytes = args[3];
1590
1591 if (out_len_bytes.size() != sizeof(uint32_t)) {
1592 return false;
1593 }
1594 const uint32_t out_len = CRYPTO_load_u32_le(out_len_bytes.data());
1595 if (out_len > (1 << 24)) {
1596 return false;
1597 }
1598
1599 std::vector<uint8_t> out(out_len);
1600 if (!::HKDF(out.data(), out_len, md, key.data(), key.size(), salt.data(),
1601 salt.size(), info.data(), info.size())) {
1602 return false;
1603 }
1604 return write_reply({out});
1605}
1606
Adam Langley480344d2023-04-13 02:09:12 +00001607template <const EVP_MD *HashFunc()>
1608static bool HKDFExtract(const Span<const uint8_t> args[],
1609 ReplyCallback write_reply) {
1610 const EVP_MD *const md = HashFunc();
1611 const auto secret = args[0];
1612 const auto salt = args[1];
1613
1614 std::vector<uint8_t> out(EVP_MD_size(md));
1615 size_t out_len;
1616 if (!HKDF_extract(out.data(), &out_len, md, secret.data(), secret.size(),
1617 salt.data(), salt.size())) {
1618 return false;
1619 }
1620 assert(out_len == out.size());
1621 return write_reply({out});
1622}
1623
1624template <const EVP_MD *HashFunc()>
1625static bool HKDFExpandLabel(const Span<const uint8_t> args[],
1626 ReplyCallback write_reply) {
1627 const EVP_MD *const md = HashFunc();
1628 const auto out_len_bytes = args[0];
1629 const auto secret = args[1];
1630 const auto label = args[2];
1631 const auto hash = args[3];
1632
1633 if (out_len_bytes.size() != sizeof(uint32_t)) {
1634 return false;
1635 }
1636 const uint32_t out_len = CRYPTO_load_u32_le(out_len_bytes.data());
1637 if (out_len > (1 << 24)) {
1638 return false;
1639 }
1640
1641 std::vector<uint8_t> out(out_len);
1642 if (!CRYPTO_tls13_hkdf_expand_label(out.data(), out_len, md, secret.data(),
1643 secret.size(), label.data(), label.size(),
1644 hash.data(), hash.size())) {
1645 return false;
1646 }
1647 return write_reply({out});
1648}
1649
Adam Langley735a8682022-05-04 16:41:11 -07001650template <bool WithReseed>
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001651static bool DRBG(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Gurleen Grewal92943062019-11-04 16:10:55 -08001652 const auto out_len_bytes = args[0];
1653 const auto entropy = args[1];
1654 const auto personalisation = args[2];
Adam Langley735a8682022-05-04 16:41:11 -07001655
1656 Span<const uint8_t> reseed_additional_data, reseed_entropy, additional_data1,
1657 additional_data2, nonce;
1658 if (!WithReseed) {
1659 additional_data1 = args[3];
1660 additional_data2 = args[4];
1661 nonce = args[5];
1662 } else {
1663 reseed_additional_data = args[3];
1664 reseed_entropy = args[4];
1665 additional_data1 = args[5];
1666 additional_data2 = args[6];
1667 nonce = args[7];
1668 }
Gurleen Grewal92943062019-11-04 16:10:55 -08001669
1670 uint32_t out_len;
1671 if (out_len_bytes.size() != sizeof(out_len) ||
1672 entropy.size() != CTR_DRBG_ENTROPY_LEN ||
Adam Langley735a8682022-05-04 16:41:11 -07001673 (!reseed_entropy.empty() &&
1674 reseed_entropy.size() != CTR_DRBG_ENTROPY_LEN) ||
Gurleen Grewal92943062019-11-04 16:10:55 -08001675 // nonces are not supported
1676 nonce.size() != 0) {
1677 return false;
1678 }
1679 memcpy(&out_len, out_len_bytes.data(), sizeof(out_len));
1680 if (out_len > (1 << 24)) {
1681 return false;
1682 }
1683 std::vector<uint8_t> out(out_len);
1684
1685 CTR_DRBG_STATE drbg;
1686 if (!CTR_DRBG_init(&drbg, entropy.data(), personalisation.data(),
1687 personalisation.size()) ||
Adam Langley735a8682022-05-04 16:41:11 -07001688 (!reseed_entropy.empty() &&
1689 !CTR_DRBG_reseed(&drbg, reseed_entropy.data(),
1690 reseed_additional_data.data(),
1691 reseed_additional_data.size())) ||
Gurleen Grewal92943062019-11-04 16:10:55 -08001692 !CTR_DRBG_generate(&drbg, out.data(), out_len, additional_data1.data(),
1693 additional_data1.size()) ||
1694 !CTR_DRBG_generate(&drbg, out.data(), out_len, additional_data2.data(),
1695 additional_data2.size())) {
1696 return false;
1697 }
1698
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001699 return write_reply({Span<const uint8_t>(out)});
Gurleen Grewal92943062019-11-04 16:10:55 -08001700}
1701
Gurleen Grewal913a2402019-11-08 18:09:41 -08001702static bool StringEq(Span<const uint8_t> a, const char *b) {
1703 const size_t len = strlen(b);
1704 return a.size() == len && memcmp(a.data(), b, len) == 0;
1705}
1706
1707static bssl::UniquePtr<EC_KEY> ECKeyFromName(Span<const uint8_t> name) {
1708 int nid;
1709 if (StringEq(name, "P-224")) {
1710 nid = NID_secp224r1;
1711 } else if (StringEq(name, "P-256")) {
1712 nid = NID_X9_62_prime256v1;
1713 } else if (StringEq(name, "P-384")) {
1714 nid = NID_secp384r1;
1715 } else if (StringEq(name, "P-521")) {
1716 nid = NID_secp521r1;
1717 } else {
1718 return nullptr;
1719 }
1720
1721 return bssl::UniquePtr<EC_KEY>(EC_KEY_new_by_curve_name(nid));
1722}
1723
1724static std::vector<uint8_t> BIGNUMBytes(const BIGNUM *bn) {
1725 const size_t len = BN_num_bytes(bn);
1726 std::vector<uint8_t> ret(len);
1727 BN_bn2bin(bn, ret.data());
1728 return ret;
1729}
1730
1731static std::pair<std::vector<uint8_t>, std::vector<uint8_t>> GetPublicKeyBytes(
1732 const EC_KEY *key) {
1733 bssl::UniquePtr<BIGNUM> x(BN_new());
1734 bssl::UniquePtr<BIGNUM> y(BN_new());
1735 if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key),
1736 EC_KEY_get0_public_key(key), x.get(),
1737 y.get(), /*ctx=*/nullptr)) {
1738 abort();
1739 }
1740
1741 std::vector<uint8_t> x_bytes = BIGNUMBytes(x.get());
1742 std::vector<uint8_t> y_bytes = BIGNUMBytes(y.get());
1743
1744 return std::make_pair(std::move(x_bytes), std::move(y_bytes));
1745}
1746
Adam Langley830e7862024-11-21 16:32:38 -08001747static bool ECDSAKeyGen(const Span<const uint8_t> args[],
1748 ReplyCallback write_reply) {
Gurleen Grewal913a2402019-11-08 18:09:41 -08001749 bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
1750 if (!key || !EC_KEY_generate_key_fips(key.get())) {
1751 return false;
1752 }
1753
1754 const auto pub_key = GetPublicKeyBytes(key.get());
1755 std::vector<uint8_t> d_bytes =
1756 BIGNUMBytes(EC_KEY_get0_private_key(key.get()));
1757
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001758 return write_reply({Span<const uint8_t>(d_bytes),
1759 Span<const uint8_t>(pub_key.first),
1760 Span<const uint8_t>(pub_key.second)});
Gurleen Grewal913a2402019-11-08 18:09:41 -08001761}
1762
1763static bssl::UniquePtr<BIGNUM> BytesToBIGNUM(Span<const uint8_t> bytes) {
1764 bssl::UniquePtr<BIGNUM> bn(BN_new());
1765 BN_bin2bn(bytes.data(), bytes.size(), bn.get());
1766 return bn;
1767}
1768
Adam Langley830e7862024-11-21 16:32:38 -08001769static bool ECDSAKeyVer(const Span<const uint8_t> args[],
1770 ReplyCallback write_reply) {
Gurleen Grewal913a2402019-11-08 18:09:41 -08001771 bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
1772 if (!key) {
1773 return false;
1774 }
1775
1776 bssl::UniquePtr<BIGNUM> x(BytesToBIGNUM(args[1]));
1777 bssl::UniquePtr<BIGNUM> y(BytesToBIGNUM(args[2]));
1778
Gurleen Grewal913a2402019-11-08 18:09:41 -08001779 uint8_t reply[1];
David Benjamin671ccb12022-10-20 16:16:50 -04001780 if (!EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()) ||
Gurleen Grewal913a2402019-11-08 18:09:41 -08001781 !EC_KEY_check_fips(key.get())) {
1782 reply[0] = 0;
1783 } else {
1784 reply[0] = 1;
1785 }
1786
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001787 return write_reply({Span<const uint8_t>(reply)});
Gurleen Grewal913a2402019-11-08 18:09:41 -08001788}
1789
1790static const EVP_MD *HashFromName(Span<const uint8_t> name) {
Adam Langleyc5dc2782021-04-22 10:00:22 -07001791 if (StringEq(name, "SHA-1")) {
1792 return EVP_sha1();
1793 } else if (StringEq(name, "SHA2-224")) {
Gurleen Grewal913a2402019-11-08 18:09:41 -08001794 return EVP_sha224();
1795 } else if (StringEq(name, "SHA2-256")) {
1796 return EVP_sha256();
1797 } else if (StringEq(name, "SHA2-384")) {
1798 return EVP_sha384();
1799 } else if (StringEq(name, "SHA2-512")) {
1800 return EVP_sha512();
Adam Langley097ffe12022-05-04 15:27:12 -07001801 } else if (StringEq(name, "SHA2-512/256")) {
1802 return EVP_sha512_256();
Gurleen Grewal913a2402019-11-08 18:09:41 -08001803 } else {
1804 return nullptr;
1805 }
1806}
1807
Adam Langley830e7862024-11-21 16:32:38 -08001808static bool ECDSASigGen(const Span<const uint8_t> args[],
1809 ReplyCallback write_reply) {
Gurleen Grewal913a2402019-11-08 18:09:41 -08001810 bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
1811 bssl::UniquePtr<BIGNUM> d = BytesToBIGNUM(args[1]);
1812 const EVP_MD *hash = HashFromName(args[2]);
1813 uint8_t digest[EVP_MAX_MD_SIZE];
1814 unsigned digest_len;
1815 if (!key || !hash ||
1816 !EVP_Digest(args[3].data(), args[3].size(), digest, &digest_len, hash,
1817 /*impl=*/nullptr) ||
1818 !EC_KEY_set_private_key(key.get(), d.get())) {
1819 return false;
1820 }
1821
1822 bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_do_sign(digest, digest_len, key.get()));
1823 if (!sig) {
1824 return false;
1825 }
1826
1827 std::vector<uint8_t> r_bytes(BIGNUMBytes(sig->r));
1828 std::vector<uint8_t> s_bytes(BIGNUMBytes(sig->s));
1829
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001830 return write_reply(
1831 {Span<const uint8_t>(r_bytes), Span<const uint8_t>(s_bytes)});
Gurleen Grewal913a2402019-11-08 18:09:41 -08001832}
1833
Adam Langley830e7862024-11-21 16:32:38 -08001834static bool ECDSASigVer(const Span<const uint8_t> args[],
1835 ReplyCallback write_reply) {
Gurleen Grewal913a2402019-11-08 18:09:41 -08001836 bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
1837 const EVP_MD *hash = HashFromName(args[1]);
1838 auto msg = args[2];
1839 bssl::UniquePtr<BIGNUM> x(BytesToBIGNUM(args[3]));
1840 bssl::UniquePtr<BIGNUM> y(BytesToBIGNUM(args[4]));
1841 bssl::UniquePtr<BIGNUM> r(BytesToBIGNUM(args[5]));
1842 bssl::UniquePtr<BIGNUM> s(BytesToBIGNUM(args[6]));
1843 ECDSA_SIG sig;
1844 sig.r = r.get();
1845 sig.s = s.get();
1846
1847 uint8_t digest[EVP_MAX_MD_SIZE];
1848 unsigned digest_len;
1849 if (!key || !hash ||
1850 !EVP_Digest(msg.data(), msg.size(), digest, &digest_len, hash,
1851 /*impl=*/nullptr)) {
1852 return false;
1853 }
1854
Gurleen Grewal913a2402019-11-08 18:09:41 -08001855 uint8_t reply[1];
David Benjamin671ccb12022-10-20 16:16:50 -04001856 if (!EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()) ||
Gurleen Grewal913a2402019-11-08 18:09:41 -08001857 !EC_KEY_check_fips(key.get()) ||
1858 !ECDSA_do_verify(digest, digest_len, &sig, key.get())) {
1859 reply[0] = 0;
1860 } else {
1861 reply[0] = 1;
1862 }
1863
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001864 return write_reply({Span<const uint8_t>(reply)});
Gurleen Grewal913a2402019-11-08 18:09:41 -08001865}
1866
Adam Langley830e7862024-11-21 16:32:38 -08001867static bool CMAC_AES(const Span<const uint8_t> args[],
1868 ReplyCallback write_reply) {
Adam Langleyfb0c05c2020-07-01 13:23:55 -07001869 uint8_t mac[16];
1870 if (!AES_CMAC(mac, args[1].data(), args[1].size(), args[2].data(),
1871 args[2].size())) {
1872 return false;
1873 }
1874
1875 uint32_t mac_len;
1876 if (args[0].size() != sizeof(mac_len)) {
1877 return false;
1878 }
1879 memcpy(&mac_len, args[0].data(), sizeof(mac_len));
1880 if (mac_len > sizeof(mac)) {
1881 return false;
1882 }
1883
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001884 return write_reply({Span<const uint8_t>(mac, mac_len)});
Adam Langleyfb0c05c2020-07-01 13:23:55 -07001885}
1886
Adam Langley830e7862024-11-21 16:32:38 -08001887static bool CMAC_AESVerify(const Span<const uint8_t> args[],
1888 ReplyCallback write_reply) {
Adam Langley4a196cc2021-01-27 16:32:59 -08001889 // This function is just for testing since libcrypto doesn't do the
1890 // verification itself. The regcap doesn't advertise "ver" support.
1891 uint8_t mac[16];
1892 if (!AES_CMAC(mac, args[0].data(), args[0].size(), args[1].data(),
1893 args[1].size()) ||
1894 args[2].size() > sizeof(mac)) {
1895 return false;
1896 }
1897
Adam Langley4d3e5402021-02-09 13:30:05 -08001898 const uint8_t ok = (OPENSSL_memcmp(mac, args[2].data(), args[2].size()) == 0);
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001899 return write_reply({Span<const uint8_t>(&ok, sizeof(ok))});
Adam Langley4a196cc2021-01-27 16:32:59 -08001900}
1901
Adam Langley830e7862024-11-21 16:32:38 -08001902static std::map<unsigned, bssl::UniquePtr<RSA>> &CachedRSAKeys() {
Adam Langleye44d9772020-10-22 16:21:09 -07001903 static std::map<unsigned, bssl::UniquePtr<RSA>> keys;
1904 return keys;
1905}
1906
Adam Langley830e7862024-11-21 16:32:38 -08001907static RSA *GetRSAKey(unsigned bits) {
Adam Langleye44d9772020-10-22 16:21:09 -07001908 auto it = CachedRSAKeys().find(bits);
1909 if (it != CachedRSAKeys().end()) {
1910 return it->second.get();
1911 }
1912
1913 bssl::UniquePtr<RSA> key(RSA_new());
1914 if (!RSA_generate_key_fips(key.get(), bits, nullptr)) {
1915 abort();
1916 }
1917
1918 RSA *const ret = key.get();
1919 CachedRSAKeys().emplace(static_cast<unsigned>(bits), std::move(key));
1920
1921 return ret;
1922}
1923
Adam Langley830e7862024-11-21 16:32:38 -08001924static bool RSAKeyGen(const Span<const uint8_t> args[],
1925 ReplyCallback write_reply) {
Adam Langley2e22d1b2020-10-22 07:56:36 -07001926 uint32_t bits;
1927 if (args[0].size() != sizeof(bits)) {
1928 return false;
1929 }
1930 memcpy(&bits, args[0].data(), sizeof(bits));
1931
1932 bssl::UniquePtr<RSA> key(RSA_new());
1933 if (!RSA_generate_key_fips(key.get(), bits, nullptr)) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001934 LOG_ERROR("RSA_generate_key_fips failed for modulus length %u.\n", bits);
Adam Langley2e22d1b2020-10-22 07:56:36 -07001935 return false;
1936 }
1937
1938 const BIGNUM *n, *e, *d, *p, *q;
1939 RSA_get0_key(key.get(), &n, &e, &d);
1940 RSA_get0_factors(key.get(), &p, &q);
1941
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001942 if (!write_reply({BIGNUMBytes(e), BIGNUMBytes(p), BIGNUMBytes(q),
1943 BIGNUMBytes(n), BIGNUMBytes(d)})) {
Adam Langleye44d9772020-10-22 16:21:09 -07001944 return false;
1945 }
1946
1947 CachedRSAKeys().emplace(static_cast<unsigned>(bits), std::move(key));
1948 return true;
1949}
1950
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001951template <const EVP_MD *(MDFunc)(), bool UsePSS>
Adam Langley830e7862024-11-21 16:32:38 -08001952static bool RSASigGen(const Span<const uint8_t> args[],
1953 ReplyCallback write_reply) {
Adam Langleye44d9772020-10-22 16:21:09 -07001954 uint32_t bits;
1955 if (args[0].size() != sizeof(bits)) {
1956 return false;
1957 }
1958 memcpy(&bits, args[0].data(), sizeof(bits));
1959 const Span<const uint8_t> msg = args[1];
1960
1961 RSA *const key = GetRSAKey(bits);
1962 const EVP_MD *const md = MDFunc();
1963 uint8_t digest_buf[EVP_MAX_MD_SIZE];
1964 unsigned digest_len;
1965 if (!EVP_Digest(msg.data(), msg.size(), digest_buf, &digest_len, md, NULL)) {
1966 return false;
1967 }
1968
1969 std::vector<uint8_t> sig(RSA_size(key));
1970 size_t sig_len;
1971 if (UsePSS) {
1972 if (!RSA_sign_pss_mgf1(key, &sig_len, sig.data(), sig.size(), digest_buf,
1973 digest_len, md, md, -1)) {
1974 return false;
1975 }
1976 } else {
1977 unsigned sig_len_u;
1978 if (!RSA_sign(EVP_MD_type(md), digest_buf, digest_len, sig.data(),
1979 &sig_len_u, key)) {
1980 return false;
1981 }
1982 sig_len = sig_len_u;
1983 }
1984
1985 sig.resize(sig_len);
1986
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001987 return write_reply(
1988 {BIGNUMBytes(RSA_get0_n(key)), BIGNUMBytes(RSA_get0_e(key)), sig});
Adam Langley2e22d1b2020-10-22 07:56:36 -07001989}
1990
Stephen Cranebc0a4f12021-02-12 15:12:29 -08001991template <const EVP_MD *(MDFunc)(), bool UsePSS>
Adam Langley830e7862024-11-21 16:32:38 -08001992static bool RSASigVer(const Span<const uint8_t> args[],
1993 ReplyCallback write_reply) {
Adam Langley777e1ff2020-10-22 16:57:56 -07001994 const Span<const uint8_t> n_bytes = args[0];
1995 const Span<const uint8_t> e_bytes = args[1];
1996 const Span<const uint8_t> msg = args[2];
1997 const Span<const uint8_t> sig = args[3];
1998
1999 BIGNUM *n = BN_new();
2000 BIGNUM *e = BN_new();
2001 bssl::UniquePtr<RSA> key(RSA_new());
2002 if (!BN_bin2bn(n_bytes.data(), n_bytes.size(), n) ||
2003 !BN_bin2bn(e_bytes.data(), e_bytes.size(), e) ||
2004 !RSA_set0_key(key.get(), n, e, /*d=*/nullptr)) {
2005 return false;
2006 }
2007
2008 const EVP_MD *const md = MDFunc();
2009 uint8_t digest_buf[EVP_MAX_MD_SIZE];
2010 unsigned digest_len;
2011 if (!EVP_Digest(msg.data(), msg.size(), digest_buf, &digest_len, md, NULL)) {
2012 return false;
2013 }
2014
2015 uint8_t ok;
2016 if (UsePSS) {
2017 ok = RSA_verify_pss_mgf1(key.get(), digest_buf, digest_len, md, md, -1,
2018 sig.data(), sig.size());
2019 } else {
2020 ok = RSA_verify(EVP_MD_type(md), digest_buf, digest_len, sig.data(),
2021 sig.size(), key.get());
2022 }
2023 ERR_clear_error();
2024
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002025 return write_reply({Span<const uint8_t>(&ok, 1)});
Adam Langley777e1ff2020-10-22 16:57:56 -07002026}
2027
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002028template <const EVP_MD *(MDFunc)()>
Adam Langley830e7862024-11-21 16:32:38 -08002029static bool TLSKDF(const Span<const uint8_t> args[],
2030 ReplyCallback write_reply) {
Adam Langleyf0400012020-12-07 15:06:13 -08002031 const Span<const uint8_t> out_len_bytes = args[0];
2032 const Span<const uint8_t> secret = args[1];
2033 const Span<const uint8_t> label = args[2];
2034 const Span<const uint8_t> seed1 = args[3];
2035 const Span<const uint8_t> seed2 = args[4];
2036 const EVP_MD *md = MDFunc();
2037
2038 uint32_t out_len;
2039 if (out_len_bytes.size() != sizeof(out_len)) {
2040 return 0;
2041 }
2042 memcpy(&out_len, out_len_bytes.data(), sizeof(out_len));
2043
2044 std::vector<uint8_t> out(static_cast<size_t>(out_len));
2045 if (!CRYPTO_tls1_prf(md, out.data(), out.size(), secret.data(), secret.size(),
2046 reinterpret_cast<const char *>(label.data()),
2047 label.size(), seed1.data(), seed1.size(), seed2.data(),
2048 seed2.size())) {
2049 return 0;
2050 }
2051
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002052 return write_reply({out});
Adam Langleyf0400012020-12-07 15:06:13 -08002053}
2054
Adam Langley0898b072020-12-08 13:44:02 -08002055template <int Nid>
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002056static bool ECDH(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Adam Langley0898b072020-12-08 13:44:02 -08002057 bssl::UniquePtr<BIGNUM> their_x(BytesToBIGNUM(args[0]));
2058 bssl::UniquePtr<BIGNUM> their_y(BytesToBIGNUM(args[1]));
2059 const Span<const uint8_t> private_key = args[2];
2060
2061 bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(Nid));
2062 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
2063
2064 const EC_GROUP *const group = EC_KEY_get0_group(ec_key.get());
2065 bssl::UniquePtr<EC_POINT> their_point(EC_POINT_new(group));
2066 if (!EC_POINT_set_affine_coordinates_GFp(
2067 group, their_point.get(), their_x.get(), their_y.get(), ctx.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002068 LOG_ERROR("Invalid peer point for ECDH.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002069 return false;
2070 }
2071
2072 if (!private_key.empty()) {
2073 bssl::UniquePtr<BIGNUM> our_k(BytesToBIGNUM(private_key));
2074 if (!EC_KEY_set_private_key(ec_key.get(), our_k.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002075 LOG_ERROR("EC_KEY_set_private_key failed.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002076 return false;
2077 }
2078
2079 bssl::UniquePtr<EC_POINT> our_pub(EC_POINT_new(group));
2080 if (!EC_POINT_mul(group, our_pub.get(), our_k.get(), nullptr, nullptr,
2081 ctx.get()) ||
2082 !EC_KEY_set_public_key(ec_key.get(), our_pub.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002083 LOG_ERROR("Calculating public key failed.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002084 return false;
2085 }
2086 } else if (!EC_KEY_generate_key_fips(ec_key.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002087 LOG_ERROR("EC_KEY_generate_key_fips failed.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002088 return false;
2089 }
2090
2091 // The output buffer is one larger than |EC_MAX_BYTES| so that truncation
2092 // can be detected.
2093 std::vector<uint8_t> output(EC_MAX_BYTES + 1);
2094 const int out_len =
2095 ECDH_compute_key(output.data(), output.size(), their_point.get(),
2096 ec_key.get(), /*kdf=*/nullptr);
2097 if (out_len < 0) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002098 LOG_ERROR("ECDH_compute_key failed.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002099 return false;
2100 } else if (static_cast<size_t>(out_len) == output.size()) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002101 LOG_ERROR("ECDH_compute_key output may have been truncated.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002102 return false;
2103 }
2104 output.resize(static_cast<size_t>(out_len));
2105
2106 const EC_POINT *pub = EC_KEY_get0_public_key(ec_key.get());
2107 bssl::UniquePtr<BIGNUM> x(BN_new());
2108 bssl::UniquePtr<BIGNUM> y(BN_new());
2109 if (!EC_POINT_get_affine_coordinates_GFp(group, pub, x.get(), y.get(),
2110 ctx.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002111 LOG_ERROR("EC_POINT_get_affine_coordinates_GFp failed.\n");
Adam Langley0898b072020-12-08 13:44:02 -08002112 return false;
2113 }
2114
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002115 return write_reply({BIGNUMBytes(x.get()), BIGNUMBytes(y.get()), output});
Adam Langley0898b072020-12-08 13:44:02 -08002116}
2117
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002118static bool FFDH(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Adam Langley28cab642020-12-10 06:59:26 -08002119 bssl::UniquePtr<BIGNUM> p(BytesToBIGNUM(args[0]));
2120 bssl::UniquePtr<BIGNUM> q(BytesToBIGNUM(args[1]));
2121 bssl::UniquePtr<BIGNUM> g(BytesToBIGNUM(args[2]));
2122 bssl::UniquePtr<BIGNUM> their_pub(BytesToBIGNUM(args[3]));
2123 const Span<const uint8_t> private_key_span = args[4];
2124 const Span<const uint8_t> public_key_span = args[5];
2125
2126 bssl::UniquePtr<DH> dh(DH_new());
2127 if (!DH_set0_pqg(dh.get(), p.get(), q.get(), g.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002128 LOG_ERROR("DH_set0_pqg failed.\n");
Adam Langley28cab642020-12-10 06:59:26 -08002129 return 0;
2130 }
2131
2132 // DH_set0_pqg took ownership of these values.
2133 p.release();
2134 q.release();
2135 g.release();
2136
2137 if (!private_key_span.empty()) {
2138 bssl::UniquePtr<BIGNUM> private_key(BytesToBIGNUM(private_key_span));
2139 bssl::UniquePtr<BIGNUM> public_key(BytesToBIGNUM(public_key_span));
2140
2141 if (!DH_set0_key(dh.get(), public_key.get(), private_key.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002142 LOG_ERROR("DH_set0_key failed.\n");
Adam Langley28cab642020-12-10 06:59:26 -08002143 return 0;
2144 }
2145
2146 // DH_set0_key took ownership of these values.
2147 public_key.release();
2148 private_key.release();
2149 } else if (!DH_generate_key(dh.get())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002150 LOG_ERROR("DH_generate_key failed.\n");
Adam Langley28cab642020-12-10 06:59:26 -08002151 return false;
2152 }
2153
Adam Langleyd09962d2021-01-25 11:28:08 -08002154 std::vector<uint8_t> z(DH_size(dh.get()));
2155 if (DH_compute_key_padded(z.data(), their_pub.get(), dh.get()) !=
2156 static_cast<int>(z.size())) {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002157 LOG_ERROR("DH_compute_key_hashed failed.\n");
Adam Langley28cab642020-12-10 06:59:26 -08002158 return false;
2159 }
2160
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002161 return write_reply({BIGNUMBytes(DH_get0_pub_key(dh.get())), z});
Adam Langley28cab642020-12-10 06:59:26 -08002162}
2163
Adam Langley830e7862024-11-21 16:32:38 -08002164template <typename PrivateKey, size_t PublicKeyBytes,
2165 bcm_status (*KeyGen)(uint8_t *, PrivateKey *, const uint8_t *),
2166 bcm_status (*MarshalPrivateKey)(CBB *, const PrivateKey *)>
2167static bool MLDSAKeyGen(const Span<const uint8_t> args[],
2168 ReplyCallback write_reply) {
2169 const Span<const uint8_t> seed = args[0];
2170 if (seed.size() != BCM_MLDSA_SEED_BYTES) {
2171 LOG_ERROR("Bad seed size.\n");
2172 return false;
2173 }
2174
2175 auto priv = std::make_unique<PrivateKey>();
2176 uint8_t pub_key_bytes[PublicKeyBytes];
2177 if (KeyGen(pub_key_bytes, priv.get(), seed.data()) != bcm_status::approved) {
2178 LOG_ERROR("ML-DSA key gen failed.\n");
2179 return false;
2180 }
2181
2182 ScopedCBB cbb;
2183 if (!CBB_init(cbb.get(), 1024) ||
2184 MarshalPrivateKey(cbb.get(), priv.get()) != bcm_status::approved ||
2185 !CBB_flush(cbb.get())) {
2186 LOG_ERROR("ML-DSA marshal failed.\n");
2187 return false;
2188 }
2189
2190 return write_reply(
2191 {pub_key_bytes, MakeConstSpan(CBB_data(cbb.get()), CBB_len(cbb.get()))});
2192}
2193
2194template <typename PrivateKey, size_t SignatureBytes,
2195 bcm_status (*ParsePrivateKey)(PrivateKey *, CBS *),
2196 bcm_status (*SignInternal)(uint8_t *, const PrivateKey *,
2197 const uint8_t *, size_t, const uint8_t *,
2198 size_t, const uint8_t *, size_t,
2199 const uint8_t *)>
2200static bool MLDSASigGen(const Span<const uint8_t> args[],
2201 ReplyCallback write_reply) {
2202 CBS cbs = bssl::MakeConstSpan(args[0]);
2203 auto priv = std::make_unique<PrivateKey>();
2204 if (ParsePrivateKey(priv.get(), &cbs) != bcm_status::approved) {
2205 LOG_ERROR("Failed to parse ML-DSA private key.\n");
2206 return false;
2207 }
2208
2209 const Span<const uint8_t> msg = args[1];
2210 const Span<const uint8_t> randomizer = args[2];
2211
2212 if (randomizer.size() != BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES) {
2213 LOG_ERROR("Bad randomizer size.\n");
2214 return false;
2215 }
2216
2217 uint8_t signature[SignatureBytes];
2218 if (SignInternal(signature, priv.get(), msg.data(), msg.size(),
2219 // It's not just an empty context, the context prefix
2220 // is omitted too.
2221 nullptr, 0, nullptr, 0,
2222 randomizer.data()) != bcm_status::approved) {
2223 LOG_ERROR("ML-DSA signing failed.\n");
2224 return false;
2225 }
2226
2227 return write_reply({signature});
2228}
2229
2230template <typename PublicKey, size_t SignatureBytes,
2231 bcm_status (*ParsePublicKey)(PublicKey *, CBS *),
2232 bcm_status (*VerifyInternal)(const PublicKey *, const uint8_t *,
2233 const uint8_t *, size_t, const uint8_t *,
2234 size_t, const uint8_t *, size_t)>
2235static bool MLDSASigVer(const Span<const uint8_t> args[],
2236 ReplyCallback write_reply) {
2237 const Span<const uint8_t> pub_key_bytes = args[0];
2238 const Span<const uint8_t> msg = args[1];
2239 const Span<const uint8_t> signature = args[2];
2240
2241 CBS cbs = bssl::MakeConstSpan(pub_key_bytes);
2242 auto pub = std::make_unique<PublicKey>();
2243 if (ParsePublicKey(pub.get(), &cbs) != bcm_status::approved) {
2244 LOG_ERROR("Failed to parse ML-DSA public key.\n");
2245 return false;
2246 }
2247
2248 if (signature.size() != SignatureBytes) {
2249 LOG_ERROR("Bad signature size.\n");
2250 return false;
2251 }
2252
2253 const uint8_t ok = bcm_success(
2254 VerifyInternal(pub.get(), signature.data(), msg.data(), msg.size(),
2255 // It's not just an empty context, the context
2256 // prefix is omitted too.
2257 nullptr, 0, nullptr, 0));
2258
2259 return write_reply({Span<const uint8_t>(&ok, sizeof(ok))});
2260}
2261
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002262static constexpr struct {
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002263 char name[kMaxNameLength + 1];
2264 uint8_t num_expected_args;
2265 bool (*handler)(const Span<const uint8_t> args[], ReplyCallback write_reply);
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002266} kFunctions[] = {
2267 {"getConfig", 0, GetConfig},
Adam Langleye24491a2022-11-25 21:23:03 +00002268 {"flush", 0, Flush},
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002269 {"SHA-1", 1, Hash<SHA1, SHA_DIGEST_LENGTH>},
2270 {"SHA2-224", 1, Hash<SHA224, SHA224_DIGEST_LENGTH>},
2271 {"SHA2-256", 1, Hash<SHA256, SHA256_DIGEST_LENGTH>},
Adam Langley4ab14ea2020-12-17 14:03:23 -08002272 {"SHA2-384", 1, Hash<SHA384, SHA384_DIGEST_LENGTH>},
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002273 {"SHA2-512", 1, Hash<SHA512, SHA512_DIGEST_LENGTH>},
Adam Langley806c5052020-11-19 10:18:19 -08002274 {"SHA2-512/256", 1, Hash<SHA512_256, SHA512_256_DIGEST_LENGTH>},
Adam Langley9fc61742021-05-06 12:15:07 -07002275 {"SHA-1/MCT", 1, HashMCT<SHA1, SHA_DIGEST_LENGTH>},
2276 {"SHA2-224/MCT", 1, HashMCT<SHA224, SHA224_DIGEST_LENGTH>},
2277 {"SHA2-256/MCT", 1, HashMCT<SHA256, SHA256_DIGEST_LENGTH>},
2278 {"SHA2-384/MCT", 1, HashMCT<SHA384, SHA384_DIGEST_LENGTH>},
2279 {"SHA2-512/MCT", 1, HashMCT<SHA512, SHA512_DIGEST_LENGTH>},
2280 {"SHA2-512/256/MCT", 1, HashMCT<SHA512_256, SHA512_256_DIGEST_LENGTH>},
Adam Langley1607f542020-11-03 15:34:57 -08002281 {"AES/encrypt", 3, AES<AES_set_encrypt_key, AES_encrypt>},
2282 {"AES/decrypt", 3, AES<AES_set_decrypt_key, AES_decrypt>},
2283 {"AES-CBC/encrypt", 4, AES_CBC<AES_set_encrypt_key, AES_ENCRYPT>},
2284 {"AES-CBC/decrypt", 4, AES_CBC<AES_set_decrypt_key, AES_DECRYPT>},
Adam Langley4ab14ea2020-12-17 14:03:23 -08002285 {"AES-CTR/encrypt", 4, AES_CTR},
2286 {"AES-CTR/decrypt", 4, AES_CTR},
Adam Langleyf94e6d72020-10-02 14:04:37 -07002287 {"AES-GCM/seal", 5, AEADSeal<AESGCMSetup>},
2288 {"AES-GCM/open", 5, AEADOpen<AESGCMSetup>},
Adam Langley8f4e9d42024-01-11 18:03:59 +00002289 {"AES-GCM-randnonce/seal", 5, AEADSeal<AESGCMRandNonceSetup>},
2290 {"AES-GCM-randnonce/open", 5, AEADOpen<AESGCMRandNonceSetup>},
Adam Langley81658a92020-09-29 14:54:09 -07002291 {"AES-KW/seal", 5, AESKeyWrapSeal},
2292 {"AES-KW/open", 5, AESKeyWrapOpen},
Adam Langleyb117a3a2020-09-29 15:36:52 -07002293 {"AES-KWP/seal", 5, AESPaddedKeyWrapSeal},
2294 {"AES-KWP/open", 5, AESPaddedKeyWrapOpen},
Adam Langleyf94e6d72020-10-02 14:04:37 -07002295 {"AES-CCM/seal", 5, AEADSeal<AESCCMSetup>},
2296 {"AES-CCM/open", 5, AEADOpen<AESCCMSetup>},
Adam Langley1607f542020-11-03 15:34:57 -08002297 {"3DES-ECB/encrypt", 3, TDES<true>},
2298 {"3DES-ECB/decrypt", 3, TDES<false>},
2299 {"3DES-CBC/encrypt", 4, TDES_CBC<true>},
2300 {"3DES-CBC/decrypt", 4, TDES_CBC<false>},
Adam Langleyd3acd452023-04-12 23:03:11 +00002301 {"HKDF/SHA2-224", 4, HKDF<EVP_sha224>},
2302 {"HKDF/SHA2-256", 4, HKDF<EVP_sha256>},
2303 {"HKDF/SHA2-384", 4, HKDF<EVP_sha384>},
2304 {"HKDF/SHA2-512", 4, HKDF<EVP_sha512>},
2305 {"HKDF/SHA2-512/256", 4, HKDF<EVP_sha512_256>},
Adam Langley480344d2023-04-13 02:09:12 +00002306 {"HKDFExpandLabel/SHA2-256", 4, HKDFExpandLabel<EVP_sha256>},
2307 {"HKDFExpandLabel/SHA2-384", 4, HKDFExpandLabel<EVP_sha384>},
2308 {"HKDFExtract/SHA2-256", 2, HKDFExtract<EVP_sha256>},
2309 {"HKDFExtract/SHA2-384", 2, HKDFExtract<EVP_sha384>},
Gurleen Grewal2085c7c2019-10-25 13:20:17 -07002310 {"HMAC-SHA-1", 2, HMAC<EVP_sha1>},
2311 {"HMAC-SHA2-224", 2, HMAC<EVP_sha224>},
2312 {"HMAC-SHA2-256", 2, HMAC<EVP_sha256>},
2313 {"HMAC-SHA2-384", 2, HMAC<EVP_sha384>},
2314 {"HMAC-SHA2-512", 2, HMAC<EVP_sha512>},
Adam Langley097ffe12022-05-04 15:27:12 -07002315 {"HMAC-SHA2-512/256", 2, HMAC<EVP_sha512_256>},
Adam Langley735a8682022-05-04 16:41:11 -07002316 {"ctrDRBG/AES-256", 6, DRBG<false>},
2317 {"ctrDRBG-reseed/AES-256", 8, DRBG<true>},
Gurleen Grewal913a2402019-11-08 18:09:41 -08002318 {"ECDSA/keyGen", 1, ECDSAKeyGen},
2319 {"ECDSA/keyVer", 3, ECDSAKeyVer},
2320 {"ECDSA/sigGen", 4, ECDSASigGen},
2321 {"ECDSA/sigVer", 7, ECDSASigVer},
Adam Langleyfb0c05c2020-07-01 13:23:55 -07002322 {"CMAC-AES", 3, CMAC_AES},
Adam Langley4a196cc2021-01-27 16:32:59 -08002323 {"CMAC-AES/verify", 3, CMAC_AESVerify},
Adam Langley2e22d1b2020-10-22 07:56:36 -07002324 {"RSA/keyGen", 1, RSAKeyGen},
Adam Langleye44d9772020-10-22 16:21:09 -07002325 {"RSA/sigGen/SHA2-224/pkcs1v1.5", 2, RSASigGen<EVP_sha224, false>},
2326 {"RSA/sigGen/SHA2-256/pkcs1v1.5", 2, RSASigGen<EVP_sha256, false>},
2327 {"RSA/sigGen/SHA2-384/pkcs1v1.5", 2, RSASigGen<EVP_sha384, false>},
2328 {"RSA/sigGen/SHA2-512/pkcs1v1.5", 2, RSASigGen<EVP_sha512, false>},
2329 {"RSA/sigGen/SHA-1/pkcs1v1.5", 2, RSASigGen<EVP_sha1, false>},
2330 {"RSA/sigGen/SHA2-224/pss", 2, RSASigGen<EVP_sha224, true>},
2331 {"RSA/sigGen/SHA2-256/pss", 2, RSASigGen<EVP_sha256, true>},
2332 {"RSA/sigGen/SHA2-384/pss", 2, RSASigGen<EVP_sha384, true>},
2333 {"RSA/sigGen/SHA2-512/pss", 2, RSASigGen<EVP_sha512, true>},
Adam Langley097ffe12022-05-04 15:27:12 -07002334 {"RSA/sigGen/SHA2-512/256/pss", 2, RSASigGen<EVP_sha512_256, true>},
Adam Langleye44d9772020-10-22 16:21:09 -07002335 {"RSA/sigGen/SHA-1/pss", 2, RSASigGen<EVP_sha1, true>},
Adam Langley777e1ff2020-10-22 16:57:56 -07002336 {"RSA/sigVer/SHA2-224/pkcs1v1.5", 4, RSASigVer<EVP_sha224, false>},
2337 {"RSA/sigVer/SHA2-256/pkcs1v1.5", 4, RSASigVer<EVP_sha256, false>},
2338 {"RSA/sigVer/SHA2-384/pkcs1v1.5", 4, RSASigVer<EVP_sha384, false>},
2339 {"RSA/sigVer/SHA2-512/pkcs1v1.5", 4, RSASigVer<EVP_sha512, false>},
2340 {"RSA/sigVer/SHA-1/pkcs1v1.5", 4, RSASigVer<EVP_sha1, false>},
2341 {"RSA/sigVer/SHA2-224/pss", 4, RSASigVer<EVP_sha224, true>},
2342 {"RSA/sigVer/SHA2-256/pss", 4, RSASigVer<EVP_sha256, true>},
2343 {"RSA/sigVer/SHA2-384/pss", 4, RSASigVer<EVP_sha384, true>},
2344 {"RSA/sigVer/SHA2-512/pss", 4, RSASigVer<EVP_sha512, true>},
Adam Langley097ffe12022-05-04 15:27:12 -07002345 {"RSA/sigVer/SHA2-512/256/pss", 4, RSASigVer<EVP_sha512_256, true>},
Adam Langley777e1ff2020-10-22 16:57:56 -07002346 {"RSA/sigVer/SHA-1/pss", 4, RSASigVer<EVP_sha1, true>},
Adam Langleyf0400012020-12-07 15:06:13 -08002347 {"TLSKDF/1.2/SHA2-256", 5, TLSKDF<EVP_sha256>},
2348 {"TLSKDF/1.2/SHA2-384", 5, TLSKDF<EVP_sha384>},
2349 {"TLSKDF/1.2/SHA2-512", 5, TLSKDF<EVP_sha512>},
Adam Langley0898b072020-12-08 13:44:02 -08002350 {"ECDH/P-224", 3, ECDH<NID_secp224r1>},
2351 {"ECDH/P-256", 3, ECDH<NID_X9_62_prime256v1>},
2352 {"ECDH/P-384", 3, ECDH<NID_secp384r1>},
2353 {"ECDH/P-521", 3, ECDH<NID_secp521r1>},
Adam Langleyd09962d2021-01-25 11:28:08 -08002354 {"FFDH", 6, FFDH},
Adam Langley830e7862024-11-21 16:32:38 -08002355 {"ML-DSA-65/keyGen", 1,
2356 MLDSAKeyGen<BCM_mldsa65_private_key, BCM_MLDSA65_PUBLIC_KEY_BYTES,
2357 BCM_mldsa65_generate_key_external_entropy,
2358 BCM_mldsa65_marshal_private_key>},
2359 {"ML-DSA-87/keyGen", 1,
2360 MLDSAKeyGen<BCM_mldsa87_private_key, BCM_MLDSA87_PUBLIC_KEY_BYTES,
2361 BCM_mldsa87_generate_key_external_entropy,
2362 BCM_mldsa87_marshal_private_key>},
2363 {"ML-DSA-65/sigGen", 3,
2364 MLDSASigGen<BCM_mldsa65_private_key, BCM_MLDSA65_SIGNATURE_BYTES,
2365 BCM_mldsa65_parse_private_key, BCM_mldsa65_sign_internal>},
2366 {"ML-DSA-87/sigGen", 3,
2367 MLDSASigGen<BCM_mldsa87_private_key, BCM_MLDSA87_SIGNATURE_BYTES,
2368 BCM_mldsa87_parse_private_key, BCM_mldsa87_sign_internal>},
2369 {"ML-DSA-65/sigVer", 3,
2370 MLDSASigVer<BCM_mldsa65_public_key, BCM_MLDSA65_SIGNATURE_BYTES,
2371 BCM_mldsa65_parse_public_key, BCM_mldsa65_verify_internal>},
2372 {"ML-DSA-87/sigVer", 3,
2373 MLDSASigVer<BCM_mldsa87_public_key, BCM_MLDSA87_SIGNATURE_BYTES,
2374 BCM_mldsa87_parse_public_key, BCM_mldsa87_verify_internal>},
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002375};
2376
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002377Handler FindHandler(Span<const Span<const uint8_t>> args) {
2378 const bssl::Span<const uint8_t> algorithm = args[0];
2379 for (const auto &func : kFunctions) {
2380 if (algorithm.size() == strlen(func.name) &&
2381 memcmp(algorithm.data(), func.name, algorithm.size()) == 0) {
2382 if (args.size() - 1 != func.num_expected_args) {
2383 LOG_ERROR("\'%s\' operation received %zu arguments but expected %u.\n",
2384 func.name, args.size() - 1, func.num_expected_args);
2385 return nullptr;
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002386 }
2387
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002388 return func.handler;
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002389 }
2390 }
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002391
2392 const std::string name(reinterpret_cast<const char *>(algorithm.data()),
2393 algorithm.size());
2394 LOG_ERROR("Unknown operation: %s\n", name.c_str());
2395 return nullptr;
Adam Langleyb7f0c1b2019-07-09 18:02:14 -07002396}
Stephen Cranebc0a4f12021-02-12 15:12:29 -08002397
2398} // namespace acvp
2399} // namespace bssl