| /* Copyright 2021 The ChromiumOS Authors |
| * 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. |
| */ |
| size_t 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 size_t 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; |
| } |
| |
| struct u2f_state *u2f_get_state_no_commit(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; |
| } |
| } |