summaryrefslogtreecommitdiff
path: root/fuzz/u2f_fuzz.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fuzz/u2f_fuzz.cc')
-rw-r--r--fuzz/u2f_fuzz.cc283
1 files changed, 283 insertions, 0 deletions
diff --git a/fuzz/u2f_fuzz.cc b/fuzz/u2f_fuzz.cc
new file mode 100644
index 0000000000..dfb46c966a
--- /dev/null
+++ b/fuzz/u2f_fuzz.cc
@@ -0,0 +1,283 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#define HIDE_EC_STDLIB
+extern "C" {
+#include "physical_presence.h"
+#include "u2f_cmds.h"
+#include "u2f_impl.h"
+#include "internal.h"
+}
+
+extern "C" {
+/******************************************************************************/
+/* Mock implementations of cr50 board.
+ */
+int system_get_chip_unique_id(uint8_t **id)
+{
+ return P256_NBYTES;
+}
+
+/******************************************************************************/
+/* Mock implementations of Dcrypto functionality.
+ */
+int DCRYPTO_x509_gen_u2f_cert_name(const p256_int *d, const p256_int *pk_x,
+ const p256_int *pk_y, const p256_int *serial,
+ const char *name, uint8_t *cert, const int n)
+{
+ memset(cert, 1, n);
+ return n;
+}
+
+enum dcrypto_result DCRYPTO_p256_key_from_bytes(
+ p256_int *x, p256_int *y, p256_int *d,
+ const uint8_t key_bytes[P256_NBYTES])
+{
+ p256_int key;
+
+ p256_from_bin(key_bytes, &key);
+
+ // The actual condition for this function to fail happens rarely,
+ // and not able to to control. So we assume it fails for some inputs
+ // for fuzz purpose.
+ if (P256_DIGIT(&key, 0) % 10 == 0) {
+ return DCRYPTO_RETRY;
+ }
+
+ if (p256_lt_blinded(&key, &SECP256r1_nMin2) >= 0)
+ return DCRYPTO_RETRY;
+ p256_add_d(&key, 1, d);
+ if (x == NULL || y == NULL)
+ return DCRYPTO_OK;
+ memset(x, 0, P256_NBYTES);
+ memset(y, 0, P256_NBYTES);
+ return DCRYPTO_OK;
+}
+
+enum dcrypto_result dcrypto_p256_ecdsa_sign(struct drbg_ctx *drbg,
+ const p256_int *key,
+ const p256_int *message,
+ p256_int *r, p256_int *s)
+{
+ memset(r, 0, sizeof(p256_int));
+ memset(s, 0, sizeof(p256_int));
+ return DCRYPTO_OK;
+}
+
+/******************************************************************************/
+/* Mock implementations of U2F functionality.
+ */
+static struct u2f_state ustate;
+struct u2f_state *u2f_get_state(void)
+{
+ return &ustate;
+}
+
+static enum touch_state tstate;
+enum touch_state pop_check_presence(int consume)
+{
+ return tstate;
+}
+
+uint8_t buffer[512];
+
+int test_fuzz_one_input(const uint8_t *data, unsigned int size)
+{
+ FuzzedDataProvider data_provider(data, size);
+
+ if (data_provider.ConsumeBool()) {
+ ustate.drbg_entropy_size = 64;
+ } else {
+ ustate.drbg_entropy_size = 32;
+ }
+
+ if (data_provider.ConsumeBool()) {
+ tstate = POP_TOUCH_YES;
+ } else {
+ tstate = POP_TOUCH_NO;
+ }
+
+ while (data_provider.remaining_bytes() > 0) {
+ std::vector<uint8_t> bytes;
+ int command_num = data_provider.ConsumeIntegralInRange(0, 2);
+
+ size_t request_size, response_size;
+ struct u2f_generate_req *generate_req;
+ struct u2f_generate_resp *generate_resp_v0;
+ struct u2f_generate_versioned_resp *generate_resp_v1;
+ struct u2f_generate_versioned_resp_v2 *generate_resp_v2;
+ struct u2f_sign_req *sign_req_v0;
+ struct u2f_sign_versioned_req *sign_req_v1;
+ struct u2f_sign_versioned_req_v2 *sign_req_v2;
+ struct u2f_attest_req *attest_req;
+ struct g2f_register_msg_v0 *g2f_msg_v0;
+ uint8_t appId[U2F_APPID_SIZE];
+ uint8_t userSecret[U2F_USER_SECRET_SIZE];
+ uint8_t authTimeSecretHash[U2F_AUTH_TIME_SECRET_SIZE];
+ uint8_t flags;
+ struct u2f_key_handle kh_0;
+ struct u2f_versioned_key_handle kh_1;
+ struct u2f_key_handle_v2 kh_2;
+ struct u2f_ec_point public_key;
+ int kh_version;
+ vendor_cmd_rc rc;
+
+ switch (command_num) {
+ case 0:
+ bytes = data_provider.ConsumeBytes<uint8_t>(
+ sizeof(struct u2f_generate_req));
+ memcpy(buffer, bytes.data(), bytes.size());
+ generate_req = (u2f_generate_req *)buffer;
+ memcpy(appId, generate_req->appId, U2F_APPID_SIZE);
+ memcpy(userSecret, generate_req->userSecret,
+ U2F_USER_SECRET_SIZE);
+ memcpy(authTimeSecretHash,
+ generate_req->authTimeSecretHash,
+ U2F_AUTH_TIME_SECRET_SIZE);
+ flags = generate_req->flags;
+ response_size = 512;
+ rc = u2f_generate_cmd(VENDOR_CC_U2F_GENERATE, buffer,
+ sizeof(struct u2f_generate_req),
+ &response_size);
+ if (rc != VENDOR_RC_SUCCESS) {
+ break;
+ }
+ if (response_size == sizeof(struct u2f_generate_resp)) {
+ kh_version = 0;
+ } else if (response_size ==
+ sizeof(struct u2f_generate_versioned_resp)) {
+ kh_version = 1;
+ } else if (response_size ==
+ sizeof(struct u2f_generate_versioned_resp_v2)) {
+ kh_version = 2;
+ } else {
+ exit(1);
+ }
+ if (kh_version == 0) {
+ generate_resp_v0 = (u2f_generate_resp *)buffer;
+ kh_0 = generate_resp_v0->keyHandle;
+ public_key = generate_resp_v0->pubKey;
+ sign_req_v0 = (u2f_sign_req *)buffer;
+ memcpy(sign_req_v0->appId, appId,
+ U2F_APPID_SIZE);
+ memcpy(sign_req_v0->userSecret, userSecret,
+ U2F_USER_SECRET_SIZE);
+ sign_req_v0->flags = flags;
+ sign_req_v0->keyHandle = kh_0;
+ bytes = data_provider.ConsumeBytes<uint8_t>(
+ U2F_P256_SIZE);
+ memcpy(sign_req_v0->hash, bytes.data(),
+ bytes.size());
+ request_size = sizeof(struct u2f_sign_req);
+ } else if (kh_version == 1) {
+ generate_resp_v1 =
+ (u2f_generate_versioned_resp *)buffer;
+ kh_1 = generate_resp_v1->keyHandle;
+ sign_req_v1 = (u2f_sign_versioned_req *)buffer;
+ memcpy(sign_req_v1->appId, appId,
+ U2F_APPID_SIZE);
+ memcpy(sign_req_v1->userSecret, userSecret,
+ U2F_USER_SECRET_SIZE);
+ sign_req_v1->flags = flags;
+ sign_req_v1->keyHandle = kh_1;
+ bytes = data_provider.ConsumeBytes<uint8_t>(
+ U2F_P256_SIZE);
+ memcpy(sign_req_v1->hash, bytes.data(),
+ bytes.size());
+ request_size =
+ sizeof(struct u2f_sign_versioned_req);
+ } else {
+ generate_resp_v2 =
+ (u2f_generate_versioned_resp_v2 *)buffer;
+ kh_2 = generate_resp_v2->keyHandle;
+ sign_req_v2 =
+ (u2f_sign_versioned_req_v2 *)buffer;
+ memcpy(sign_req_v2->appId, appId,
+ U2F_APPID_SIZE);
+ memcpy(sign_req_v2->userSecret, userSecret,
+ U2F_USER_SECRET_SIZE);
+ memcpy(sign_req_v2->authTimeSecret,
+ authTimeSecretHash,
+ U2F_AUTH_TIME_SECRET_SIZE);
+ sign_req_v2->flags = flags;
+ sign_req_v2->keyHandle = kh_2;
+ bytes = data_provider.ConsumeBytes<uint8_t>(
+ U2F_P256_SIZE);
+ memcpy(sign_req_v2->hash, bytes.data(),
+ bytes.size());
+ request_size = sizeof(
+ struct u2f_sign_versioned_req_v2);
+ }
+ response_size = 512;
+ u2f_sign_cmd(VENDOR_CC_U2F_SIGN, buffer, request_size,
+ &response_size);
+ if (kh_version == 0) {
+ attest_req = (u2f_attest_req *)buffer;
+ attest_req->format = U2F_ATTEST_FORMAT_REG_RESP;
+ attest_req->dataLen =
+ sizeof(struct g2f_register_msg_v0);
+ memcpy(attest_req->userSecret, userSecret,
+ U2F_USER_SECRET_SIZE);
+ g2f_msg_v0 =
+ (g2f_register_msg_v0 *)attest_req->data;
+ g2f_msg_v0->reserved = 0;
+ memcpy(g2f_msg_v0->app_id, appId,
+ U2F_APPID_SIZE);
+ memcpy(g2f_msg_v0->key_handle.hmac, kh_0.hmac,
+ sizeof(kh_0.hmac));
+ memcpy(g2f_msg_v0->key_handle.origin_seed,
+ kh_0.origin_seed,
+ sizeof(kh_0.origin_seed));
+ g2f_msg_v0->public_key = public_key;
+ bytes = data_provider.ConsumeBytes<uint8_t>(
+ U2F_CHAL_SIZE);
+ memcpy(g2f_msg_v0->challenge, bytes.data(),
+ bytes.size());
+ response_size = 512;
+ u2f_attest_cmd(VENDOR_CC_U2F_ATTEST, buffer,
+ sizeof(struct u2f_attest_req),
+ &response_size);
+ }
+ break;
+ case 1: {
+ int version =
+ data_provider.ConsumeIntegralInRange(0, 2);
+ request_size =
+ (version == 0) ?
+ sizeof(struct u2f_sign_req) :
+ (version == 1) ?
+ sizeof(struct u2f_sign_versioned_req) :
+ sizeof(struct u2f_sign_versioned_req_v2);
+ bytes = data_provider.ConsumeBytes<uint8_t>(
+ request_size);
+ memcpy(buffer, bytes.data(), bytes.size());
+ response_size = 512;
+ u2f_sign_cmd(VENDOR_CC_U2F_SIGN, buffer, request_size,
+ &response_size);
+ break;
+ }
+ case 2:
+ auto str = data_provider.ConsumeRandomLengthString(256);
+ memcpy(buffer, str.data(), str.size());
+ attest_req = (u2f_attest_req *)buffer;
+ attest_req->dataLen =
+ sizeof(struct g2f_register_msg_v0);
+ response_size = 512;
+ u2f_attest_cmd(VENDOR_CC_U2F_ATTEST, buffer, str.size(),
+ &response_size);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+} \ No newline at end of file