Initial check-in of TF-Fuzz.
Author: Gary Morrison <gary.morrison@arm.com>
Signed-off-by: Gary Morrison <gary.morrison@arm.com>
Change-Id: I8f739c3403bf2a2808f33c28910c7bda6aca7887
diff --git a/tools/tf_fuzz/utility/README b/tools/tf_fuzz/utility/README
new file mode 100644
index 0000000..012fefd
--- /dev/null
+++ b/tools/tf_fuzz/utility/README
@@ -0,0 +1,15 @@
+.../tf_fuzz/utility directory contents:
+
+compute.cpp find_or_create_asset.hpp randomization.cpp string_ops.hpp
+compute.hpp gibberish.cpp randomization.hpp
+data_blocks.cpp gibberish.hpp Source.cpp
+data_blocks.hpp interactive.c string_ops.cpp
+
+--------------------------------------------------------------------------------
+
+As its name implies, this .../utility directory just contains various utility-
+compute "stuff."
+
+--------------
+
+*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
diff --git a/tools/tf_fuzz/utility/compute.cpp b/tools/tf_fuzz/utility/compute.cpp
new file mode 100644
index 0000000..708a1f3
--- /dev/null
+++ b/tools/tf_fuzz/utility/compute.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <cstdint> // for uint32_t
+#include "compute.hpp"
+
+
+using namespace std;
+
+/**********************************************************************************
+ Methods of class crc32 follow:
+**********************************************************************************/
+
+crc32::crc32 (void)
+{
+ shift_reg = 0x55555555; // just give it some default value
+}
+
+void crc32::seed_lfsr (uint32_t init_value)
+{
+ shift_reg = init_value;
+}
+
+/* lfsr_1b() performs one shift of the LFSR, factoring in a single bit of info,
+ that single bit must be in the low-order bit of the parameter. It returns
+ the LFSR value, which may be ignored. */
+uint32_t crc32::lfsr_1b (uint32_t a_bit)
+{
+ bool odd;
+
+ odd = ((shift_reg ^ a_bit) & 1) == 1;
+ shift_reg >>= 1;
+ if (odd) {
+ shift_reg ^= polynomial;
+ }
+ if (shift_reg == 0) {
+ // Theoretically should never happen, but precaution...
+ seed_lfsr (0x55555555);
+ }
+ return shift_reg;
+}
+
+uint32_t crc32::crc (uint8_t a_byte)
+{
+ for (int i = 0; i < 8; i++) {
+ lfsr_1b ((uint32_t) a_byte);
+ a_byte >>= 1;
+ }
+ return shift_reg;
+}
+
+uint32_t crc32::crc (uint16_t a_halfword)
+{
+ for (int i = 0; i < 16; i++) {
+ lfsr_1b ((uint32_t) a_halfword);
+ a_halfword >>= 1;
+ }
+ return shift_reg;
+}
+
+uint32_t crc32::crc (uint32_t a_word)
+{
+ for (int i = 0; i < 32; i++) {
+ lfsr_1b ((uint32_t) a_word);
+ a_word >>= 1;
+ }
+ return shift_reg;
+}
+
+/**********************************************************************************
+ End of methods of class crc32.
+**********************************************************************************/
diff --git a/tools/tf_fuzz/utility/compute.hpp b/tools/tf_fuzz/utility/compute.hpp
new file mode 100644
index 0000000..c6ece6c
--- /dev/null
+++ b/tools/tf_fuzz/utility/compute.hpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef COMPUTE_HPP
+#define COMPUTE_HPP
+
+#include <cstdlib>
+
+using namespace std;
+
+/* Arguably at least, this LFSR-based hashing code is run more commonly on the
+ target itself -- included in the generated code -- than it is run here.
+ However, it's available here too, such as to parallel-calculate expected hash
+ values. */
+
+class crc32
+{
+public:
+ void seed_lfsr (uint32_t init_value);
+ /* lfsr_1b() performs one shift of the LFSR, factoring in a single bit of info,
+ that single bit must be in the low-order bit of the parameter. */
+ uint32_t lfsr_1b (uint32_t a_bit);
+ // crc() has two overloadings, calculating the CRC for byte or word quantities:
+ uint32_t crc (uint8_t a_byte);
+ uint32_t crc (uint16_t a_halfword);
+ uint32_t crc (uint32_t a_word);
+ crc32 (void);
+private:
+ const uint32_t polynomial = 0xb4bcd35c;
+ uint32_t shift_reg;
+};
+
+#endif /* COMPUTE_HPP */
diff --git a/tools/tf_fuzz/utility/data_blocks.cpp b/tools/tf_fuzz/utility/data_blocks.cpp
new file mode 100644
index 0000000..172d672
--- /dev/null
+++ b/tools/tf_fuzz/utility/data_blocks.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/* These classes "cut down the clutter" by grouping together related data and
+ associated methods (most importantly their constructors) used in template_
+ line, psa_call, psa_asset (etc.). */
+
+#include <string>
+#include <vector>
+#include <cstdint>
+
+#include "class_forwards.hpp"
+
+#include "boilerplate.hpp"
+#include "gibberish.hpp"
+#include "compute.hpp"
+#include "string_ops.hpp"
+#include "data_blocks.hpp"
+#include "psa_asset.hpp"
+#include "crypto_asset.hpp"
+#include "find_or_create_asset.hpp"
+#include "psa_call.hpp"
+#include "template_line.hpp"
+#include "tf_fuzz.hpp"
+
+
+
+/**********************************************************************************
+ Methods of class expect_info follow:
+**********************************************************************************/
+
+expect_info::expect_info (void) // (default constructor)
+{
+ pf_nothing = false; // by default, TF-Fuzz provides expected results
+ pf_pass = pf_specified = false;
+ pf_result_string.assign (""); data.assign ("");
+ data_var_specified = false;
+ data_var.assign (""); // name of expected-data variable
+ data_specified = false;
+ data.assign ("");
+ pf_info_incomplete = true;
+}
+expect_info::~expect_info (void) // (destructor)
+{}
+
+void expect_info::set_pf_pass (void)
+{
+ pf_pass = true;
+ pf_nothing = pf_specified = false;
+ pf_result_string = "";
+}
+
+void expect_info::set_pf_nothing (void)
+{
+ pf_nothing = true;
+ pf_pass = pf_specified = false;
+ pf_result_string = "";
+}
+
+void expect_info::set_pf_error (string error)
+{
+ pf_specified = true;
+ pf_result_string.assign (error); // just default "guess," to be filled in
+ pf_pass = pf_nothing = false;
+}
+
+/* What the call expects is not available from the parser until the call has already
+ been created. The flag, pf_info_incomplete, that indicates whether or not the
+ "expects" information has been filled in If not, fill it in from the template,
+ once that info has been parsed. */
+void expect_info::copy_expect_to_call (psa_call *the_call)
+{
+ the_call->expect.pf_nothing = pf_nothing;
+ the_call->expect.pf_pass = pf_pass;
+ the_call->expect.pf_specified = pf_specified;
+ the_call->expect.pf_result_string = pf_result_string;
+ the_call->expect.pf_info_incomplete = false;
+}
+
+/**********************************************************************************
+ End of methods of class expect_info.
+**********************************************************************************/
+
+
+/**********************************************************************************
+ Class set_data_info methods regarding setting and getting asset-data values:
+**********************************************************************************/
+
+set_data_info::set_data_info (void) // (default constructor)
+{
+ literal_data_not_file = true; // currently, not using files as data sources
+ string_specified = false;
+ data.assign ("");
+ random_data = false;
+ file_specified = false;
+ file_path.assign ("");
+}
+set_data_info::~set_data_info (void) // (destructor)
+{}
+
+/* set() establishes:
+ * An asset's data value from a template line (e.g., set sst snort data "data
+ value"), and
+ * *That* such a value was directly specified, as opposed to no data value having
+ been specified, or a random data value being requested.
+ Arguably, this method "has side effects," in that it not only sets a value, but
+ also "takes notes" about where that value came from.
+*/
+void set_data_info::set (string set_val)
+{
+ literal_data_not_file = true; // currently, not using files as data sources
+ string_specified = true;
+ data.assign (set_val);
+}
+
+/* set_calculated() establishes:
+ * An asset's data value as *not* taken from a template line, and
+ * *That* such a value was not directly specified in any template line, such as
+ if a random data value being requested.
+ Arguably, this method "has side effects," in that it not only sets a value, but
+ also "takes notes" about where that value came from.
+*/
+void set_data_info::set_calculated (string set_val)
+{
+ literal_data_not_file = true; // currently, not using files as data sources
+ string_specified = false;
+ data.assign (set_val);
+}
+
+/* Getter for protected member, data. Protected so that it can only be set by
+ set() or set_calculated(), above, to establish not only its value but
+ how it came about. */
+string set_data_info::get (void)
+{
+ return data;
+}
+
+/* Currently, files as data sources aren't used, so this whole method is not "of
+ use," but that might change at some point. */
+bool set_data_info::set_file (string file_name)
+{
+ literal_data_not_file = true;
+ string_specified = false;
+ data.assign ("");
+ file_specified = true;
+ // Remove the ' ' quotes around the file name:
+ file_name.erase (0, 1);
+ file_name.erase (file_name.length()-1, 1);
+ file_path = file_name;
+ return true;
+}
+
+/**********************************************************************************
+ End of methods of class set_data_info.
+**********************************************************************************/
+
+
+/**********************************************************************************
+ Class asset_name_id_info methods regarding setting and getting asset-data values:
+**********************************************************************************/
+
+asset_name_id_info::asset_name_id_info (void) // (default constructor)
+{
+ id_n_not_name = false; // (arbitrary)
+ id_n = 100 + (rand() % 10000); // default to random ID# (e.g., SST UID)
+ asset_name.assign ("");
+ id_n_specified = name_specified = false; // no ID info yet
+ asset_name_vector.clear();
+ asset_id_n_vector.clear();
+}
+asset_name_id_info::~asset_name_id_info (void)
+{
+ asset_name_vector.clear();
+ asset_id_n_vector.clear();
+}
+
+/* set_name() establishes:
+ * An asset's "human" name from a template line, and
+ * *That* that name was directly specified, as opposed to the asset being defined
+ by ID only, or a random name being requested.
+ Arguably, this method "has side effects," in that it not only sets a name, but
+ also "takes notes" about where that name came from.
+*/
+void asset_name_id_info::set_name (string set_val)
+{
+ /* Use this to set the name as specified in the template file. Call this only
+ if the template file does indeed define a name. */
+ name_specified = true;
+ asset_name = set_val;
+}
+
+/* set_calc_name() establishes:
+ * An asset's "human" name *not* from a template line, and
+ * *That* that name was *not* directly specified in any template line.
+ Arguably, this method "has side effects," in that it not only sets a name, but
+ also "takes notes" about where that name came from.
+*/
+void asset_name_id_info::set_calc_name (string set_val)
+{
+ name_specified = false;
+ asset_name = set_val;
+}
+
+// set_just_name() sets an asset's "human" name, without noting how that name came up.
+void asset_name_id_info::set_just_name (string set_val)
+{
+ asset_name = set_val;
+}
+
+/* Getter for protected member, asset_name. Protected so that it can only be set by
+ set_name() or set_calc_name(), above, to establish not only its value but
+ how it came about. */
+string asset_name_id_info::get_name (void)
+{
+ return asset_name;
+}
+
+// Asset IDs can be set directly from a uint64_t or converted from a string:
+void asset_name_id_info::set_id_n (string set_val)
+{
+ id_n = stol (set_val, 0, 0);
+}
+void asset_name_id_info::set_id_n (uint64_t set_val)
+{
+ id_n = set_val;
+}
+
+// Create ID-based name:
+string asset_name_id_info::make_id_n_based_name (uint64_t id_n, string &name)
+{
+ string result = "SST_ID_";
+ result.append(to_string(id_n));
+ return result;
+}
+
+/**********************************************************************************
+ End of methods of class asset_name_id_info.
+**********************************************************************************/
diff --git a/tools/tf_fuzz/utility/data_blocks.hpp b/tools/tf_fuzz/utility/data_blocks.hpp
new file mode 100644
index 0000000..2822f57
--- /dev/null
+++ b/tools/tf_fuzz/utility/data_blocks.hpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string>
+
+/* These classes "cut down the clutter" by grouping together related data and
+ associated methods (most importantly their constructors) used in template_
+ line, psa_call, psa_asset (etc.). */
+
+#ifndef DATA_BLOCKS_HPP
+#define DATA_BLOCKS_HPP
+
+/* This project's header files #including other project headers quickly becomes
+ unrealistically complicated. The only solution is for each .cpp to include
+ the headers it needs. However these in particular are mostly axiomatic: Not
+ dependent upon other classes. */
+
+
+using namespace std;
+
+
+/**********************************************************************************
+ Class expect_info is all about expected data and expected pass/fail information.
+ The members are therefore broken down with prefixes pf_ (for pass/fail) or
+ data_. Pass/fail, is broadly:
+ * "Pass" == the test passes
+ * "Specified" == some specified failure (e.g., no such asset)
+ * "Nothing" == no expectation
+ Expected data refers to psa-asset data values, generally after reading them.
+ Currently, they are limited to character strings, but that will probably be
+ generalized in the future.
+**********************************************************************************/
+
+class expect_info
+{
+public:
+ // Data members:
+ bool pf_nothing; // true to not generate results-check(s)
+ bool pf_pass; // if !expect.pf_nothing, then pass is expected
+ bool pf_specified;
+ /* if !pf_nothing && !pf_pass, then
+ true == expected result was specified
+ false == tf_fuzz must model expected result */
+ bool data_specified; // (literal data specified)
+ string data; // expected data from reading an asset
+ bool data_var_specified;
+ string data_var; // name of variable containing expected data
+ bool pf_info_incomplete;
+ /* In parsing the template, the expect information comes later than the
+ rest of the call info. This flag tells us to fill in the expect
+ info when it comes available. */
+ // Expected-result info:
+ string pf_result_string;
+ // if !pf_nothing && !pf_pass then this is expected result
+ // Methods:
+ expect_info (void); // (default constructor)
+ ~expect_info (void); // (destructor)
+ void set_pf_pass (void);
+ void set_pf_nothing (void);
+ void set_pf_error (string error);
+ void copy_expect_to_call (psa_call *the_call);
+
+protected:
+ // Data members:
+ bool data_matches_asset;
+ /* true if template specifies expected data, and that expected data
+ agrees with that in the asset */
+};
+
+
+/**********************************************************************************
+ Class set_data_info addresses PSA-asset data values as affected, directly or
+ indirctly/implicitly, by the template-line content. "Directly," that is, by
+ virtue of the template line stating verbatim what to set data to, or indirectly
+ by virtue of telling TF-Fuzz to create random data for it.
+**********************************************************************************/
+
+class set_data_info
+{
+public:
+ // Data members:
+ bool string_specified;
+ // true if a string of expected data is specified in template file
+ bool random_data; // true to generate random data for the asset
+ bool file_specified; // true if a file of expected data was specified
+ bool literal_data_not_file;
+ // true to use data strings rather than files as data source
+ string file_path; // path to file, if specified
+ // Methods:
+ set_data_info (void); // (default constructor)
+ ~set_data_info (void); // (destructor)
+ void set (string set_val);
+ void set_calculated (string set_val);
+ string get (void);
+ bool set_file (string file_name);
+
+protected:
+ // Data members:
+ string data; // String describing asset data.
+};
+
+
+/**********************************************************************************
+ Class asset_name_id_info groups together and acts upon all information related to the
+ human names (as reflected in the code variable names, etc.) for PSA assets.
+**********************************************************************************/
+
+class asset_name_id_info
+{
+public:
+ // Data members (not much value in "hiding" these behind getters)
+ bool id_n_not_name; // true to create a PSA asset by ID
+ bool name_specified; // true iff template supplied human name
+ bool id_n_specified; // true iff template supplied ID #
+ vector<string> asset_name_vector;
+ vector<int> asset_id_n_vector;
+ uint64_t id_n; // asset ID# (e.g., SST UID).
+ /* Note: This is just a holder to pass ID from template-line to call.
+ The IDs for a given template line are in asset_id.asset_id_n_vector. */
+ // Methods:
+ asset_name_id_info (void); // (default constructor)
+ ~asset_name_id_info (void); // (destructor)
+ void set_name (string set_val);
+ void set_calc_name (string set_val);
+ void set_just_name (string set_val);
+ string get_name (void);
+ void set_id_n (string set_val);
+ void set_id_n (uint64_t set_val);
+ string make_id_n_based_name (uint64_t id_n, string &name);
+ // create UID-based asset name
+
+protected:
+ // Data members:
+ string asset_name; // parsed from template, assigned to psa_asset object
+};
+
+
+
+#endif // DATA_BLOCKS_HPP
+
diff --git a/tools/tf_fuzz/utility/find_or_create_asset.hpp b/tools/tf_fuzz/utility/find_or_create_asset.hpp
new file mode 100644
index 0000000..866c949
--- /dev/null
+++ b/tools/tf_fuzz/utility/find_or_create_asset.hpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FIND_OR_CREATE_ASSET_HPP
+#define FIND_OR_CREATE_ASSET_HPP
+
+/* This enum defines possible results when asked to find an existing, or create a
+ new PSA asset. */
+enum class asset_search
+{ found_active, // found as an actively-used asset
+ found_deleted, // found as a previously-used, but now-unusable asset
+ found_invalid, // found as a previously-used, but now-unusable asset
+ not_found, // if not found and if not allowed to create it
+ created_new, // no such existing asset was found so created new one
+ unsuccessful, // ran out of memory or whatever
+ something_wrong // something wrong with the code; shouldn't happen
+};
+// Search areas:
+enum class psa_asset_usage // one particular area or all
+{ active, // found as an actively-used asset
+ deleted, // found as a previously-used, but now-unusable asset
+ invalid, // found as a previously-used, but now-unusable asset
+ all, // if not found and if not allowed to create it
+ none // just create it
+};
+// In searching for an asset, this enum specifies what to search for:
+enum class psa_asset_search
+{ name, // its human name
+ id, // its id, such as SST UID
+ serial // its serial number assigned upon creation
+};
+// Types of assets:
+enum class psa_asset_type
+{ sst, // (pretty obvious what each of these mean)
+ key,
+ policy
+};
+
+
+// A few consts just to make code more readable:
+const bool yes_create_asset = true;
+const bool dont_create_asset = false;
+
+
+/* There are several variants, by asset type, of this method. So, C++ templating
+ is best. Note that, while the vectors are pointers to the base, psa_asset type,
+ the individual entries are all of the same ASSET_TYPE type. */
+template <typename ASSET_TYPE>
+asset_search generic_find_or_create_asset (
+ vector<psa_asset*> &active_asset_vector, // the three vectors of known assets
+ vector<psa_asset*> &deleted_asset_vector,
+ vector<psa_asset*> &invalid_asset_vector,
+ psa_asset_search criterion, // what to search on
+ psa_asset_usage where, // where to search
+ string target_name, // ignored if not searching on name
+ uint64_t target_id, // also ignored if not searching on ID (e.g., SST UID)
+ long &serial_no, // search on this if requested, but return serial regardless
+ bool create_asset, // true to create the asset if it doesn't exist
+ typename vector<psa_asset*>::iterator &asset
+ // returns iterator to the requested asset
+) {
+ ASSET_TYPE *new_asset;
+ bool match = false; // match found
+ // Look first in active assets:
+ if (where == psa_asset_usage::active || where == psa_asset_usage::all) {
+ for (auto as = active_asset_vector.begin(); as < active_asset_vector.end();
+ ++as) {
+ psa_asset *pass = *as;
+ switch (criterion) {
+ case psa_asset_search::name: // human-meaningful name
+ match = (pass->asset_id.get_name() == target_name);
+ break;
+ case psa_asset_search::id: // ID#
+ match = (pass->asset_id.id_n == target_id);
+ break;
+ default: // psa_asset_search::serial
+ match = (pass->asset_ser_no == serial_no);
+ break;
+ }
+ if (match) {
+ asset = as;
+ return asset_search::found_active;
+ }
+ }
+ }
+ // Look then in deleted assets:
+ if (where == psa_asset_usage::deleted || where == psa_asset_usage::all) {
+ for (auto as = deleted_asset_vector.begin(); as < deleted_asset_vector.end();
+ ++as) {
+ psa_asset *pass = *as;
+ switch (criterion) {
+ case psa_asset_search::name: // human-meaningful name
+ match = (pass->asset_id.get_name() == target_name);
+ break;
+ case psa_asset_search::id: // ID#
+ match = (pass->asset_id.id_n == target_id);
+ break;
+ default: // psa_asset_search::serial
+ match = (pass->asset_ser_no == serial_no);
+ break;
+ }
+ if (match) {
+ asset = as;
+ return asset_search::found_deleted;
+ }
+ }
+ }
+ // Look then in invalid assets:
+ if (where == psa_asset_usage::invalid || where == psa_asset_usage::all) {
+ for (auto as = invalid_asset_vector.begin(); as < invalid_asset_vector.end();
+ ++as) {
+ psa_asset *pass = *as;
+ switch (criterion) {
+ case psa_asset_search::name: // human-meaningful name
+ match = (pass->asset_id.get_name() == target_name);
+ break;
+ case psa_asset_search::id: // ID#
+ match = (pass->asset_id.id_n == target_id);
+ break;
+ default: // psa_asset_search::serial
+ match = (pass->asset_ser_no == serial_no);
+ break;
+ }
+ if (match) {
+ asset = as;
+ return asset_search::found_invalid;
+ }
+ }
+ }
+ // Couldn't find it in any of the existing lists, so create it in active assets:
+ if (create_asset) {
+ try {
+ new_asset = new ASSET_TYPE;
+ if (criterion == psa_asset_search::id) {
+ new_asset->asset_id.id_n = target_id;
+ } // TO DO: probably should do the same for its name in a name search!
+ active_asset_vector.push_back(new_asset);
+ asset = prev(active_asset_vector.end());
+ return asset_search::created_new;
+ }
+ catch (std::bad_alloc& bad) {
+ std::cerr << "Error: Failed to allocate an ASSET_TYPE: " << bad.what()
+ << endl;
+ return asset_search::unsuccessful;
+ }
+ } else {
+ return asset_search::not_found;
+ }
+ return asset_search::something_wrong; // should never get here
+}
+
+#endif // ifndef FIND_OR_CREATE_ASSET_HPP
diff --git a/tools/tf_fuzz/utility/gibberish.cpp b/tools/tf_fuzz/utility/gibberish.cpp
new file mode 100644
index 0000000..45ce223
--- /dev/null
+++ b/tools/tf_fuzz/utility/gibberish.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * These functions produce random-gibberish quasi-words in a quasi-sentence.
+ * Random character streams may be conceptually sufficient, but for testing
+ * purposes, it's much easier for humans to remember and to distinguish semi-
+ * pro-nounceable gibberish like "dokwab neltiegib..." than
+ * "f7H%r^&B*5|j6@Mz>\#...".
+ */
+
+#include <string>
+
+#include "gibberish.hpp" // shouldn't need any other project headers
+
+
+/**
+ * \brief Returns a letter for random-gibberish quasi-words in a quasi-sentence.
+ *
+ * \return A letter character value.
+ *
+ */
+char gibberish::letter(void)
+{
+ return 'a' + (rand() % ('z'-'a' + 1));
+}
+
+
+/**
+ * \brief Returns a vowel for random-gibberish quasi-words in a quasi-sentence.
+ *
+ * \return A vowel character value.
+ *
+ */
+char gibberish::vowel(void)
+{
+ char vowels[] = "aeiou";
+
+ return vowels[rand() % 5];
+}
+
+
+/**
+ * \brief Returns a consonant for random-gibberish quasi-words in a quasi-sentence.
+ *
+ * \return A consonant character value.
+ *
+ */
+char gibberish::consonant(void)
+{
+ char candidate;
+
+ do {
+ candidate = letter();
+ } while ( candidate == 'a' || candidate == 'e' || candidate == 'i'
+ || candidate == 'o' || candidate == 'u');
+ return candidate;
+}
+
+
+/**
+ * \brief Appends a semi-pronounceable syllable onto a string, stopping before
+ * the end of the string, for random-gibberish quasi-words in a
+ * quasi-sentence. Returns a pointer to the next open spot in the string.
+ *
+ * \param[in] string_ptr Pointer to where to put the word.
+ *
+ * \param[in] stop Pointer to last character in quasi-sentence.
+ *
+ * \return Pointer to first character after the word.
+ *
+ */
+char *gibberish::syllable (char *string_ptr, char *stop)
+{
+ char *parser; /* points into string while building it */
+
+ parser = string_ptr;
+ if ((rand() % 4) < 3) {
+ if (parser < stop) *parser++ = consonant();
+ if (parser < stop) *parser++ = vowel();
+ if (parser < stop) *parser++ = letter();
+ } else {
+ if (parser < stop) *parser++ = vowel();
+ if (((rand() % 4) < 1) && parser < stop) {
+ *parser++ = vowel();
+ }
+ if (parser < stop) *parser++ = consonant();
+ }
+ return parser;
+}
+
+
+/**
+ * \brief Appends a mostly-pronounceable quasi-word onto a quasi-sentence string,
+ * stopping before the end of the string. Returns a pointer to the next
+ * open spot in the string.
+ *
+ * \param[in] initial_cap: True if the first character should be capitalized.
+ *
+ * \param[in] string_ptr Pointer to where to put the word.
+ *
+ * \param[in] stop Pointer to last character in quasi-sentence.
+ *
+ * \return Pointer to first character after the word.
+ *
+ */
+char *gibberish::word (bool initial_cap, char *string_ptr, char *stop)
+{
+ int syllable_count;
+ char *parser; /* points into string while building it */
+
+ for (syllable_count = 0, parser = string_ptr;
+ syllable_count < 4
+ && (rand() % 4) >= syllable_count
+ && parser < stop;
+ syllable_count++) {
+ parser = syllable (parser, stop);
+ }
+ if (initial_cap) {
+ *string_ptr -= 'a' - 'A'; /* more or less assumes ASCII */
+ }
+ return parser;
+}
+
+
+/**
+ * \brief Creates a mostly-pronounceable, random-gibberish quasi-sentence,
+ * stopping before the end of the string.
+ *
+ * \param[in] string_ptr Pointer to beginning of string for quasi-sentence.
+ *
+ * \param[in] stop Pointer to last character in quasi-sentence.
+ *
+ */
+void gibberish::sentence (char *string_ptr, char *stop)
+{
+ char *parser; /* points into string while building it */
+ char punctuation[] = ".?!";
+
+ *stop = '\0'; /* null-terminate the string */
+ --stop;
+ parser = word (capitalize, string_ptr, stop);
+ if (parser < stop) {
+ *parser++ = ' ';
+ }
+ for (; parser < stop; ) {
+ parser = word (dont_capitalize, parser, stop);
+ if (parser < stop) {
+ *parser++ = ' ';
+ }
+ }
+ parser--;
+ if (*parser == ' ') {
+ *parser = vowel(); // just to not have a blank at the end
+ }
+ *stop = punctuation[rand() % 3];
+}
+
+
+/**
+ * \brief Chooses a gibberish-sentence length.
+ *
+ */
+int gibberish::pick_sentence_len (void)
+{
+ return min_literal_data_len + (rand() % literal_data_len_span);
+}
+
+
+/**
+ * \brief Constructor for gibberish object.
+ *
+ */
+gibberish::gibberish (void)
+{
+ // Nothing to set up.
+}
+
+
+/**
+ * \brief Destructor for gibberish object.
+ *
+ */
+gibberish::~gibberish (void)
+{
+ // Nothing to tear down.
+}
diff --git a/tools/tf_fuzz/utility/gibberish.hpp b/tools/tf_fuzz/utility/gibberish.hpp
new file mode 100644
index 0000000..5efd419
--- /dev/null
+++ b/tools/tf_fuzz/utility/gibberish.hpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * sec-regress.c&.h implement the Scripted-Call Application, and other functions
+ * for the security-regression testing feature.
+ *
+ */
+
+#ifndef GIBBERISH_HPP
+#define GIBBERISH_HPP
+
+#include <cstdlib>
+
+using namespace std;
+
+class gibberish
+{
+public: // not much value in hiding these behind getters and setters
+ // Data members:
+ static const int min_literal_data_len = 32, max_literal_data_len = 512,
+ literal_data_len_span = max_literal_data_len - min_literal_data_len;
+ // Methods:
+ gibberish (void); // (constructor)
+ ~gibberish (void);
+ char letter (void);
+ char vowel (void);
+ char consonant (void);
+ char *syllable (char *string_ptr, char *stop);
+ char *word (bool initial_cap, char *string_ptr, char *stop);
+ int pick_sentence_len (void);
+ void sentence (char *string_ptr, char *stop);
+
+protected:
+ // Data members:
+ // Methods:
+
+private:
+ // Data members:
+ static const bool capitalize = true;
+ static const bool dont_capitalize = false;
+ // Parameters of random SST-asset generation:
+ // Methods:
+};
+
+#endif /* GIBBERISH_HPP */
diff --git a/tools/tf_fuzz/utility/randomization.cpp b/tools/tf_fuzz/utility/randomization.cpp
new file mode 100644
index 0000000..8abfe5c
--- /dev/null
+++ b/tools/tf_fuzz/utility/randomization.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**********************************************************************************
+ Functions in this file are exactly that: functions, not methods of any class.
+ That is, they are stand-alone, utility functions linked in to the executable,
+ and available to whomever needs them.
+**********************************************************************************/
+
+#include "randomization.hpp"
+
+/**
+ * \brief Selects and returns a random key_usage_t value.
+ *
+ * \details
+ *
+ * \note
+ *
+ */
+string rand_key_usage (void)
+{
+ switch (rand() % 6) {
+ case 0: return "PSA_KEY_USAGE_EXPORT";
+ case 1: return "PSA_KEY_USAGE_ENCRYPT";
+ case 2: return "PSA_KEY_USAGE_DECRYPT";
+ case 3: return "PSA_KEY_USAGE_SIGN";
+ case 4: return "PSA_KEY_USAGE_VERIFY";
+ case 5: return "PSA_KEY_USAGE_DERIVE";
+ }
+ return ""; /* placate compiler */
+}
+
+/**
+ * \brief Selects and returns a random psa_algorithm_t value.
+ *
+ * \details
+ *
+ * \note
+ *
+ */
+/* TODO: Likely want to make additional versions of these specific for TLS,
+ asymmetric, symmetric... */
+string rand_key_algorithm (void)
+{
+ switch (rand() % 47) {
+ case 0: return "PSA_ALG_VENDOR_FLAG";
+ case 1: return "PSA_ALG_CATEGORY_MASK";
+ case 2: return "PSA_ALG_CATEGORY_HASH";
+ case 3: return "PSA_ALG_CATEGORY_MAC";
+ case 4: return "PSA_ALG_CATEGORY_CIPHER";
+ case 5: return "PSA_ALG_CATEGORY_AEAD";
+ case 6: return "PSA_ALG_CATEGORY_SIGN";
+ case 7: return "PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION";
+ case 8: return "PSA_ALG_CATEGORY_KEY_AGREEMENT";
+ case 9: return "PSA_ALG_CATEGORY_KEY_DERIVATION";
+ case 10: return "PSA_ALG_CATEGORY_KEY_SELECTION";
+ case 11: return "PSA_ALG_KEY_SELECTION_FLAG";
+ case 12: return "PSA_ALG_HASH_MASK";
+ case 13: return "PSA_ALG_MD2";
+ case 14: return "PSA_ALG_MD4";
+ case 15: return "PSA_ALG_MD5";
+ case 16: return "PSA_ALG_RIPEMD160";
+ case 17: return "PSA_ALG_SHA_1";
+ case 18: return "PSA_ALG_SHA_224";
+ case 19: return "PSA_ALG_SHA_256";
+ case 20: return "PSA_ALG_SHA_384";
+ case 21: return "PSA_ALG_SHA_512";
+ case 22: return "PSA_ALG_SHA_512_224";
+ case 23: return "PSA_ALG_SHA_512_256";
+ case 24: return "PSA_ALG_SHA3_224";
+ case 25: return "PSA_ALG_SHA3_256";
+ case 26: return "PSA_ALG_SHA3_384";
+ case 27: return "PSA_ALG_SHA3_512";
+ case 28: return "PSA_ALG_ANY_HASH";
+ case 29: return "PSA_ALG_MAC_SUBCATEGORY_MASK";
+ case 30: return "PSA_ALG_HMAC_BASE";
+ case 31: return "PSA_ALG_MAC_TRUNCATION_MASK";
+ case 32: return "PSA_ALG_CIPHER_MAC_BASE";
+ case 33: return "PSA_ALG_CBC_MAC";
+ case 34: return "PSA_ALG_CMAC";
+ case 35: return "PSA_ALG_GMAC";
+ case 36: return "PSA_ALG_CIPHER_STREAM_FLAG";
+ case 37: return "PSA_ALG_CIPHER_FROM_BLOCK_FLAG";
+ case 38: return "PSA_ALG_ARC4";
+ case 39: return "PSA_ALG_CTR";
+ case 40: return "PSA_ALG_CFB";
+ case 41: return "PSA_ALG_OFB";
+ case 42: return "PSA_ALG_XTS";
+ case 43: return "PSA_ALG_CBC_NO_PADDING";
+ case 44: return "PSA_ALG_CBC_PKCS7";
+ case 45: return "PSA_ALG_CCM";
+ case 46: return "PSA_ALG_GCM";
+ }
+ return ""; /* placate compiler */
+}
+
+
+/**
+ * \brief Selects and returns a random psa_key_type_t value.
+ *
+ * \details
+ *
+ * \note
+ *
+ */
+string rand_key_type (void)
+{
+ switch (rand() % 22) {
+ case 0: return "PSA_KEY_TYPE_NONE";
+ case 1: return "PSA_KEY_TYPE_VENDOR_FLAG";
+ case 2: return "PSA_KEY_TYPE_CATEGORY_MASK";
+ case 3: return "PSA_KEY_TYPE_CATEGORY_SYMMETRIC";
+ case 4: return "PSA_KEY_TYPE_CATEGORY_RAW";
+ case 5: return "PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY";
+ case 6: return "PSA_KEY_TYPE_CATEGORY_KEY_PAIR";
+ case 7: return "PSA_KEY_TYPE_CATEGORY_FLAG_PAIR";
+ case 8: return "PSA_KEY_TYPE_RAW_DATA";
+ case 9: return "PSA_KEY_TYPE_HMAC";
+ case 10: return "PSA_KEY_TYPE_DERIVE";
+ case 11: return "PSA_KEY_TYPE_AES";
+ case 12: return "PSA_KEY_TYPE_DES";
+ case 13: return "PSA_KEY_TYPE_CAMELLIA";
+ case 14: return "PSA_KEY_TYPE_ARC4";
+ case 15: return "PSA_KEY_TYPE_RSA_PUBLIC_KEY";
+ case 16: return "PSA_KEY_TYPE_RSA_KEYPAIR";
+ case 17: return "PSA_KEY_TYPE_DSA_PUBLIC_KEY";
+ case 18: return "PSA_KEY_TYPE_DSA_KEYPAIR";
+ case 19: return "PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE";
+ case 20: return "PSA_KEY_TYPE_ECC_KEYPAIR_BASE";
+ case 21: return "PSA_KEY_TYPE_ECC_CURVE_MASK";
+ default: return "";
+ }
+ return ""; /* placate compiler */
+}
+
diff --git a/tools/tf_fuzz/utility/randomization.hpp b/tools/tf_fuzz/utility/randomization.hpp
new file mode 100644
index 0000000..2eb72f6
--- /dev/null
+++ b/tools/tf_fuzz/utility/randomization.hpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef RANDOMIZATION_HPP
+#define RANDOMIZATION_HPP
+
+#include <string>
+
+using namespace std;
+
+string rand_key_usage (void);
+
+string rand_key_algorithm (void);
+
+string rand_key_type (void);
+
+#endif /* #ifndef RANDOMIZATION_HPP */
diff --git a/tools/tf_fuzz/utility/string_ops.cpp b/tools/tf_fuzz/utility/string_ops.cpp
new file mode 100644
index 0000000..a25a777
--- /dev/null
+++ b/tools/tf_fuzz/utility/string_ops.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "string_ops.hpp"
+
+using namespace std;
+
+// Replace first occurrence of find_str within orig of replace_str:
+size_t find_replace_1st (const string &find_str, const string &replace_str,
+ string &orig) {
+ size_t where = 0;
+ where = orig.find(find_str, where);
+ if (where != string::npos) {
+ orig.replace(where, find_str.length(), replace_str);
+ }
+ return where;
+}
+
+// Replace all occurrences of find_str in "this" string, with replace_str:
+size_t find_replace_all (const string &find_str, const string &replace_str,
+ string &orig) {
+ size_t where = 0;
+ do {
+ where = orig.find(find_str, where);
+ if (where != string::npos) {
+ orig.replace(where, find_str.length(), replace_str);
+ }
+ } while (where != string::npos);
+ return where;
+}
diff --git a/tools/tf_fuzz/utility/string_ops.hpp b/tools/tf_fuzz/utility/string_ops.hpp
new file mode 100644
index 0000000..697a342
--- /dev/null
+++ b/tools/tf_fuzz/utility/string_ops.hpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef STRING_OPS_HPP
+#define STRING_OPS_HPP
+
+#include <cstddef>
+#include <string>
+
+using namespace std;
+
+// Replace first occurrence of find_str within orig of replace_str:
+size_t find_replace_1st (const string &find_str, const string &replace_str,
+ string &orig);
+
+// Replace all occurrences of find_str in "this" string, with replace_str:
+size_t find_replace_all (const string &find_str, const string &replace_str,
+ string &orig);
+
+/* In both of the above string-replacement functions, the return value is start
+ offset to the (last) occurrence of "find_str" within "orig." */
+
+#endif // #ifndef STRING_OPS_HPP