blob: c9763aa927fd50d28524b2ce9114ada3e34cd9f4 [file] [log] [blame]
/*
* Copyright (c) 2019-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdexcept>
#include <stdlib.h>
#include <iostream>
#include "boilerplate.hpp"
#include "crypto_asset.hpp"
#include "string_ops.hpp"
#include "data_blocks.hpp"
#include "psa_asset.hpp"
#include "find_or_create_asset.hpp"
#include "tf_fuzz.hpp"
#include "psa_call.hpp"
/**********************************************************************************
Methods of class psa_call follow:
**********************************************************************************/
//**************** psa_call methods ****************
psa_call::psa_call (tf_fuzz_info *test_state, long &call_ser_no, // (constructor)
asset_search how_asset_found)
{
this->test_state = test_state;
this->asset_info.how_asset_found = how_asset_found;
set_data.string_specified = false;
set_data.set (""); // actual data
assign_data_var.assign (""); // name of variable assigned (dumped) to
assign_data_var_specified = false;
set_data.file_specified = false;
set_data.file_path.assign ("");
this->call_ser_no = call_ser_no = unique_id_counter++;
// These will be set in the lower-level constructors, but...
prep_code = call_code = check_code = "";
print_data = hash_data = false;
barrier = target_barrier = ""; // not (yet) any barrier for re-ordering calls
call_description = "";
}
psa_call::~psa_call (void)
{
return; // just to have something to pin a breakpoint onto
}
void psa_call::write_out_prep_code (ofstream &test_file)
{
test_file << prep_code;
}
void psa_call::write_out_command (ofstream &test_file)
{
test_file << call_code;
}
void psa_call::write_out_check_code (ofstream &test_file)
{
if (exp_data.result_code_checking_enabled()) {
test_file << check_code;
} else {
test_file << " /* (No checks for this PSA call.) */" << endl;
}
}
bool psa_call::simulate(void) {
return false;
}
void psa_call::copy_policy_to_call(void) {
string name = policy.get_policy_from_policy;
// name represents the policy asset we want to use for this call.
// We don't want to use a policy asset, so we have nothing to do here.
if (name == ""){
return;
}
vector<psa_asset*>::iterator found_asset;
long x; // doesnt matter
asset_search status = test_state->find_or_create_policy_asset(psa_asset_search::name,psa_asset_usage::all,name,0,x,dont_create_asset,found_asset);
switch (status) {
case asset_search::found_active:
case asset_search::found_deleted:
case asset_search::found_invalid:
break;
default:
cerr << "Fatal: could not find policy asset " << name << endl;
exit(1);
}
string handle = policy.handle_str;
string asset_2_name = policy.asset_2_name;
string asset_3_name = policy.asset_3_name;
policy = found_asset[0]->policy;
policy.handle_str = handle;
policy.asset_2_name = asset_2_name;
policy.asset_3_name = asset_3_name;
}
/**********************************************************************************
End of methods of class psa_call.
**********************************************************************************/
/**********************************************************************************
Methods of class sst_call follow:
**********************************************************************************/
/* calc_result_code() fills in the check_code string member with the correct
result code (e.g., "PSA_SUCCESS" or whatever).
This is a big part of where the target modeling -- error modeling -- occurs,
so lots of room for further refinement here. */
void sst_call::fill_in_result_code (void)
{
string formalized; // "proper" result string
switch (exp_data.get_expected_return_code()) {
case expected_return_code_t::DontCare: // Do not generate checks
return;
case expected_return_code_t::Pass:
find_replace_all ("$expect",
test_state->bplate->bplate_string[sst_pass_string],
check_code);
// `check "foo"`
find_replace_all ("$check_expect",
"0",
check_code);
break;
case expected_return_code_t::Fail:
// If the command is `... check "foo" expect fail;`, the fail
// binds to the check, not the command itself.
if (exp_data.data_specified) {
// expect a pass for the sst call itself.
find_replace_all ("$expect",
test_state->bplate->bplate_string[sst_pass_string],
check_code);
// expect a failure for the check.
find_replace_all ("!= $check_expect",
"== 0",
check_code);
find_replace_1st ("should be equal", "should not be equal",
check_code);
} else {
// Check for not-success:
find_replace_1st ("!=", "==",
check_code);
find_replace_all ("$expect",
test_state->bplate->bplate_string[sst_pass_string],
check_code);
find_replace_1st ("expected ", "expected not ",
check_code);
}
break;
case expected_return_code_t::SpecificFail:
formalized = formalize (exp_data.get_expected_return_code_string(), "PSA_ERROR_");
find_replace_all ("$expect", formalized, check_code);
// NOTE: Assumes that the variable used to store the actual
// value initialised to a different value than the expected
// value.
find_replace_all ("!= $check_expect","== 0",check_code);
find_replace_1st ("should be equal", "should not be equal",
check_code);
break;
// TODO: move error code simulation into simulate().
case expected_return_code_t::DontKnow: // Simulate
// Figure out what the message should read:
switch (asset_info.how_asset_found) {
case asset_search::found_active:
case asset_search::created_new:
find_replace_all ("$expect",
test_state->bplate->
bplate_string[sst_pass_string],
check_code);
find_replace_all ("$check_expect","0",check_code);
break;
case asset_search::found_deleted:
case asset_search::not_found:
find_replace_all ("$expect",
test_state->bplate->
bplate_string[sst_fail_removed],
check_code);
// NOTE: Assumes that the variable used to store the actual
// value initialised to a different value than the expected
// value.
find_replace_all ("!= $check_expect","== 0",check_code);
find_replace_1st ("should be equal", "should not be equal",
check_code);
break;
default:
find_replace_1st ("!=", "==",
check_code); // like "fail", just make sure...
find_replace_all ("$expect",
test_state->bplate->
bplate_string[sst_pass_string],
check_code); // ... it's *not* PSA_SUCCESS
// NOTE: Assumes that the variable used to store the actual
// value initialised to a different value than the expected
// value.
find_replace_all ("!= $check_expect","== 0",check_code);
find_replace_1st ("should be equal", "should not be equal",
check_code);
break;
}
break;
}
}
vector<psa_asset*>::iterator sst_call::resolve_asset (bool create_asset_bool,
psa_asset_usage where) {
vector<psa_asset*>::iterator found_asset;
vector<psa_asset*> *asset_vector;
int asset_pick;
if (random_asset != psa_asset_usage::all) {
// != psa_asset_usage::all means to choose some known asset at random:
if (random_asset == psa_asset_usage::active) {
asset_vector = &(test_state->active_sst_asset);
asset_info.how_asset_found = asset_search::found_active;
} else if (random_asset == psa_asset_usage::deleted) {
asset_vector = &(test_state->deleted_sst_asset);
asset_info.how_asset_found = asset_search::found_deleted;
} else {
// "invalid" assets are not currently used.
cerr << "\nError: Tool-internal: Please report error 1101 to " << endl
<< "TF-Fuzz developers."
<< endl;
exit(1101);
}
if (asset_vector->size() > 0) {
/* Pick an active or deleted asset at random: */
asset_pick = rand() % asset_vector->size();
found_asset = asset_vector->begin() + asset_pick;
/* Copy asset information into template tracker: */
asset_info.id_n = (*found_asset)->asset_info.id_n;
asset_info.asset_ser_no
= (*found_asset)->asset_info.asset_ser_no;
} else {
if (random_asset == psa_asset_usage::active) {
cerr << "\nError: An sst call asks for a "
<< "randomly chosen active asset, when none " << endl
<< "is currently defined." << endl;
exit(1008);
} else if (random_asset == psa_asset_usage::deleted) {
cerr << "\nError: An sst call asks for a "
<< "randomly chosen deleted asset, when none " << endl
<< "is currently defined." << endl;
exit(1009);
} // "invalid" assets are not currently used.
}
} else {
// Find the asset by name:
asset_info.how_asset_found = test_state->find_or_create_sst_asset (
psa_asset_search::name, where,
asset_info.get_name(), 0, asset_info.asset_ser_no,
create_asset_bool, found_asset );
if ( asset_info.how_asset_found == asset_search::unsuccessful
|| asset_info.how_asset_found == asset_search::something_wrong ) {
cerr << "\nError: Tool-internal: Please report error 108 to " << endl
<< "TF-Fuzz developers."
<< endl;
exit(108);
}
}
return found_asset;
}
sst_call::sst_call (tf_fuzz_info *test_state, long &call_ser_no, // (constructor)
asset_search how_asset_found)
: psa_call(test_state, call_ser_no, how_asset_found)
{
asset_info.the_asset = nullptr;
return; // just to have something to pin a breakpoint onto
}
sst_call::~sst_call (void)
{
return; // just to have something to pin a breakpoint onto
}
/**********************************************************************************
End of methods of class sst_call.
**********************************************************************************/
/**********************************************************************************
Methods of class crypto_call follow:
**********************************************************************************/
bool crypto_call::simulate(void) {
bool has_changed = false;
has_changed |= simulate_ret_code();
return has_changed;
}
bool crypto_call::simulate_ret_code(void) {
if (!exp_data.simulation_needed()) {
return false;
}
switch (asset_info.how_asset_found) {
case asset_search::found_active:
case asset_search::created_new:
exp_data.expect_pass();
return true;
case asset_search::not_found:
case asset_search::found_deleted:
exp_data.expect_failure();
return true;
default:
exp_data.expect_failure();
return true;
}
}
/* calc_result_code() fills in the check_code string member with the correct
result code (e.g., "PSA_SUCCESS" or whatever). This "modeling" needs to be
improved and expanded upon *massively* more or less mirroring what is seen in
.../test/suites/crypto/crypto_tests_common.c in the psa_key_interface_test()
method, (starting around line 20ish). */
void crypto_call::fill_in_result_code (void)
{
string formalized; // "proper" result string
switch (exp_data.get_expected_return_code()) {
case expected_return_code_t::DontCare:
return;
case expected_return_code_t::Pass:
find_replace_all ("$expect",
test_state->bplate->bplate_string[sst_pass_string],
check_code);
break;
case expected_return_code_t::Fail:
// Check for not-success:
find_replace_1st ("!=", "==",
check_code);
find_replace_all ("$expect",
test_state->bplate->bplate_string[sst_pass_string],
check_code);
find_replace_1st ("expected ", "expected not ",
check_code);
break;
case expected_return_code_t::SpecificFail:
formalized = formalize (exp_data.get_expected_return_code_string(), "PSA_ERROR_");
find_replace_all ("$expect", formalized, check_code);
break;
case expected_return_code_t::DontKnow: // Simulate -- SHOULD NEVER HAPPEN
throw std::logic_error("Crypto call fill_in_result_code: return code is don't know");
}
}
bool crypto_call::copy_asset_to_call (void)
{
if (asset_info.the_asset == nullptr) {
return false;
} else {
// Get updated asset info from the asset:
asset_info.asset_ser_no = asset_info.the_asset->asset_info.asset_ser_no;
asset_info.id_n = asset_info.the_asset->asset_info.id_n;
exp_data.n_exp_vars = asset_info.the_asset->exp_data.n_exp_vars;
exp_data.data = asset_info.the_asset->exp_data.data;
return true;
}
}
crypto_call::crypto_call (tf_fuzz_info *test_state, long &call_ser_no, // (constructor)
asset_search how_asset_found)
: psa_call(test_state, call_ser_no, how_asset_found)
{
policy = key_policy_info::create_random();
return; // just to have something to pin a breakpoint onto
}
crypto_call::~crypto_call (void)
{
// Nothing further to delete.
return; // just to have something to pin a breakpoint onto
}
/**********************************************************************************
End of methods of class crypto_call.
**********************************************************************************/
/**********************************************************************************
Methods of class security_call follow:
**********************************************************************************/
security_call::security_call (tf_fuzz_info *test_state, long &call_ser_no, // (constructor)
asset_search how_asset_found)
: psa_call(test_state, call_ser_no, how_asset_found)
{
// Nothing further to initialize.
return; // just to have something to pin a breakpoint onto
}
security_call::~security_call (void)
{
// Nothing further to delete.
return; // just to have something to pin a breakpoint onto
}
// resolve_asset() doesn't do anything for security_calls, since there's no asset involved.
vector<psa_asset*>::iterator security_call::resolve_asset (bool create_asset_bool,
psa_asset_usage where)
{
return test_state->active_sst_asset.end(); // (anything)
}
/* calc_result_code() fills in the check_code string member with the correct result
code (e.g., "PSA_SUCCESS" or whatever).
Since there are no actual PSA calls associated with security calls (so far at least),
this should never be invoked. */
void security_call::fill_in_result_code (void)
{
// Currently should not be invoked.
cerr << "\nError: Internal: Please report error #205 to TF-Fuzz developers." << endl;
exit (205);
}
/**********************************************************************************
End of methods of class security_call.
**********************************************************************************/