tf_fuzz: add new crypto key generation model

* Add a new model of what it means for a crypto policy to be valid. This
  fixes the simulation of psa_generate_key() calls, which TF-Fuzz
  currently cannot accurately predict.

  The PSA Crypto properties modelled are whether an algorithm and key
  type are compatible, whether a key type/ algorithm are disabled, and
  what key sizes are allowed.

  Although the PSA Crypto specification has additional, more complicated
  requirements for policies and keys, this commit only implements what
  is necessary for predicting the outcome of psa_generate_key(), and not
  requirements that make a key useless but still valid or involve
  features not yet in TF-M or MbedTLS.

* Improve the way in which policies are filled in, and allow policies to
  be updated at simulation time using the value of a named policy asset.
  Information about other assets and calls is not accessible during
  parse time when the key policy is usually filled in. However, this is
  required for the improved simulation of psa_generate_key calls. This
  is because policy information for generate key calls come from a named
  policy created earlier in the test file.

* Add valid flag to set-policy calls, allowing the creation of a random
  valid policy. For example, see demo/36.test.

* Add demo/36.test. This test generates a policy with a (roughly) even
  chance of being valid or invalid and then tries to generate a key
  using it.

  Running this test a large number of times (~300) succeeds with the
  changes in this commit, showing that TF-Fuzz can now accurately
  predict the outcome of psa_generate_key calls.

Change-Id: Ia40ff893db50b8d2c579d975aa23341b7aab004d
Signed-off-by: Nik Dewally <Nik.Dewally@arm.com>
diff --git a/tf_fuzz/demo/17.test b/tf_fuzz/demo/17.test
deleted file mode 100644
index bdaeece..0000000
--- a/tf_fuzz/demo/17.test
+++ /dev/null
@@ -1,8 +0,0 @@
-purpose to try some more-complex randomization;
-set sst name neil buzz mike data *;
-2 to 5 of {
-    set sst name neil data "that's one small step for [a] man";
-    remove sst *active;
-    set sst name chris kraft data "wear the helmet";
-    remove sst name neil;
-}
diff --git a/tf_fuzz/demo/25.5.test b/tf_fuzz/demo/25.5.test
new file mode 100644
index 0000000..cea2279
--- /dev/null
+++ b/tf_fuzz/demo/25.5.test
@@ -0,0 +1,3 @@
+purpose to create a random valid policy and create a key using it (no key material specified);
+set policy name randomPolicy valid;
+set key name akey policy randomPolicy;
diff --git a/tf_fuzz/demo/28.test b/tf_fuzz/demo/28.test
index e9fd0d8..0faee18 100644
--- a/tf_fuzz/demo/28.test
+++ b/tf_fuzz/demo/28.test
@@ -1,4 +1,4 @@
 purpose to create a key, then read the key data ("material") into a variable;
-set policy name somePolicy alg sha3_224 attr noexport volatile;
+set policy name somePolicy alg cfb attr noexport volatile valid;
 set key name aKey data * policy somePolicy;
 read key name aKey var keyDataVar;
diff --git a/tf_fuzz/demo/29.test b/tf_fuzz/demo/29.test.disabled
similarity index 100%
rename from tf_fuzz/demo/29.test
rename to tf_fuzz/demo/29.test.disabled
diff --git a/tf_fuzz/demo/36.test b/tf_fuzz/demo/36.test
new file mode 100644
index 0000000..fc8e4cf
--- /dev/null
+++ b/tf_fuzz/demo/36.test
@@ -0,0 +1,12 @@
+purpose to have a more even chance of creating a valid or invalid key;
+
+/*
+ most completely random keys will be invalid so something like this helps get
+ more valid keys into the mix
+ */
+
+1 of {
+set policy name randomPolicy valid;
+set policy name randomPolicy;
+}
+set key name akey policy randomPolicy;
diff --git a/tf_fuzz/tfz-cpp/Makefile b/tf_fuzz/tfz-cpp/Makefile
index 488b675..e0a099f 100644
--- a/tf_fuzz/tfz-cpp/Makefile
+++ b/tf_fuzz/tfz-cpp/Makefile
@@ -3,10 +3,11 @@
 # SPDX-License-Identifier: BSD-3-Clause
 
 CXX = g++
-INCLUDES = -I /usr/include -I . -I ./parser -I ./template -I ./assets -I ./calls -I ./boilerplate -I ./utility
-override CXXFLAGS += -std=gnu++11 -O0 -g $(INCLUDES)
+INCLUDES = -I /usr/include -I . -I ./parser -I ./template -I ./assets -I ./calls -I ./boilerplate -I ./utility -I ./crypto_model
+override CXXFLAGS += -std=gnu++17 -Werror=return-type -O0 -g $(INCLUDES)
 
 sources = $(wildcard assets/*.cpp) \
+          $(wildcard crypto_model/*.cpp) \
 		  $(wildcard boilerplate/*.cpp) \
 		  $(wildcard calls/*.cpp) \
 		  $(wildcard template/*.cpp) \
@@ -74,8 +75,8 @@
 
 .PHONY: clean
 clean:
-	rm -f tfz *.d **/*.d *.d* **/*.d* $(objs) $(generated_objs) $(generated_includes) $(generated_sources)\
-	parser/tf_fuzz_grammar.output
+	rm -f tfz *.d **/*.d *.d* **/*.d* $(objs) $(generated_objs) $(generated_includes) $(generated_sources)
+	rm -rf parser/tf_fuzz_grammar.lex.c parser/tf_fuzz_grammar.output
 	rm -f `find regression -name "stdout_stderr"`
 	rm -f `find regression -name "test.c"`
 	rm -f demo/tossThis*
diff --git a/tf_fuzz/tfz-cpp/assets/crypto_asset.cpp b/tf_fuzz/tfz-cpp/assets/crypto_asset.cpp
index 7c493af..ab7963b 100644
--- a/tf_fuzz/tfz-cpp/assets/crypto_asset.cpp
+++ b/tf_fuzz/tfz-cpp/assets/crypto_asset.cpp
@@ -8,6 +8,7 @@
 #include <stdlib.h>
 
 #include "gibberish.hpp"
+#include "data_blocks.hpp"
 #include "crypto_asset.hpp"
 
 
@@ -18,6 +19,7 @@
 
 crypto_asset::crypto_asset (void)  // (default constructor)
 {
+    policy = key_policy_info::create_random();
     return;  // just to have something to pin a breakpoint onto
 }
 
@@ -65,9 +67,7 @@
 
 key_asset::key_asset (void)
 {
-    // Note:  Similar random initialization for asset and template
     // Randomize handle:
-    // TODO:  Key handles appear to be a lot more complex a question than the below
     gibberish *gib = new gibberish;
     char buffer[256];
     char *end;
diff --git a/tf_fuzz/tfz-cpp/calls/crypto_call.cpp b/tf_fuzz/tfz-cpp/calls/crypto_call.cpp
index b800baa..c9d000d 100644
--- a/tf_fuzz/tfz-cpp/calls/crypto_call.cpp
+++ b/tf_fuzz/tfz-cpp/calls/crypto_call.cpp
@@ -20,7 +20,9 @@
 #include "crypto_asset.hpp"
 #include "psa_call.hpp"
 #include "crypto_call.hpp"
+#include "crypto_model.hpp"
 
+using namespace crypto_model;
 
 /**********************************************************************************
    Methods of class policy_call follow:
@@ -958,7 +960,50 @@
 
 bool generate_key_call::copy_call_to_asset (void)
 {
-    return copy_call_to_asset_t<key_asset*> (this, yes_create_asset);
+    // we create the asset conditionally in simulate
+    return copy_call_to_asset_t<key_asset*> (this, dont_create_asset);
+}
+
+bool generate_key_call::simulate() {
+    bool is_policy_valid;
+
+    // NOTE: although algorithm and key-type depend on eachother for validity,
+    // this is checked during key operations not generation
+
+
+    if (policy.key_type == "PSA_KEY_TYPE_RSA_PUBLIC_KEY") {
+        is_policy_valid = false;
+    }
+    else if (policy.key_type == "PSA_KEY_TYPE_PEPPER") {
+        is_policy_valid = false;
+    } else {
+        key_type& kt = get_key_type(policy.key_type);
+        algorithm& alg = get_algorithm(policy.key_algorithm);
+        is_policy_valid = kt.is_valid_key_size(policy.n_bits);
+    }
+
+    psa_asset_usage asset_usage;
+
+    if (!is_policy_valid) {
+        // do not create a key when policy is invalid
+        exp_data.expect_failure();
+        return true;
+    }
+
+    // create an asset, and copy the information we want in it to it.
+    copy_call_to_asset_t<key_asset*> (this, yes_create_asset);
+    switch (asset_info.how_asset_found) {
+    case asset_search::created_new:
+        exp_data.expect_pass();
+
+        break;
+
+    default: // asset already exists!
+        exp_data.expect_failure();
+        break;
+    }
+
+    return true;
 }
 
 void generate_key_call::fill_in_prep_code (void)
@@ -1011,9 +1056,10 @@
     return;  // just to have something to pin a breakpoint onto
 }
 
+
 bool create_key_call::copy_call_to_asset (void)
 {
-    return copy_call_to_asset_t<key_asset*> (this, yes_create_asset);
+    return copy_call_to_asset_t<key_asset*> (this, dont_create_asset);
 }
 
 void create_key_call::fill_in_prep_code (void)
@@ -1324,6 +1370,30 @@
     return;  // just to have something to pin a breakpoint onto
 }
 
+bool remove_key_call::simulate () {
+    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;
+
+        // if the asset never existed, its handle will be null.
+        // deleting the null handle succeeds
+        case asset_search::not_found:
+            exp_data.expect_pass();
+            return true;
+
+        case asset_search::found_deleted:
+            exp_data.expect_failure();
+            return true;
+        default:
+            exp_data.expect_failure();
+            return true;
+    }
+}
 bool remove_key_call::copy_call_to_asset (void)
 {
     return copy_call_to_asset_t<key_asset*> (this, dont_create_asset);
diff --git a/tf_fuzz/tfz-cpp/calls/crypto_call.hpp b/tf_fuzz/tfz-cpp/calls/crypto_call.hpp
index ff43b45..9d6b457 100644
--- a/tf_fuzz/tfz-cpp/calls/crypto_call.hpp
+++ b/tf_fuzz/tfz-cpp/calls/crypto_call.hpp
@@ -465,9 +465,10 @@
 public:
     // Data members:
     // Methods:
-        bool copy_call_to_asset (void);
-        void fill_in_prep_code (void);
-        void fill_in_command (void);
+        bool copy_call_to_asset (void) override;
+        void fill_in_prep_code (void) override;
+        void fill_in_command (void) override;
+        bool simulate (void) override;
         generate_key_call (tf_fuzz_info *test_state, long &asset_ser_no,
                          asset_search how_asset_found);  // (constructor)
         ~generate_key_call (void);
@@ -488,9 +489,9 @@
 public:
     // Data members:
     // Methods:
-        bool copy_call_to_asset (void);
-        void fill_in_prep_code (void);
-        void fill_in_command (void);
+        bool copy_call_to_asset (void) override;
+        void fill_in_prep_code (void) override;
+        void fill_in_command (void) override;
         create_key_call (tf_fuzz_info *test_state, long &asset_ser_no,
                          asset_search how_asset_found);  // (constructor)
         ~create_key_call (void);
@@ -560,6 +561,7 @@
         bool copy_call_to_asset (void) override;
         void fill_in_prep_code (void) override;
         void fill_in_command (void) override;
+        bool simulate (void) override;
         remove_key_call (tf_fuzz_info *test_state, long &asset_ser_no,
                          asset_search how_asset_found);  // (constructor)
         ~remove_key_call (void);
diff --git a/tf_fuzz/tfz-cpp/calls/psa_call.cpp b/tf_fuzz/tfz-cpp/calls/psa_call.cpp
index 7ca407e..c9763aa 100644
--- a/tf_fuzz/tfz-cpp/calls/psa_call.cpp
+++ b/tf_fuzz/tfz-cpp/calls/psa_call.cpp
@@ -5,10 +5,12 @@
  *
  */
 
+#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"
@@ -71,6 +73,43 @@
     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.
 **********************************************************************************/
@@ -273,6 +312,34 @@
    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
@@ -309,32 +376,8 @@
         find_replace_all ("$expect", formalized, check_code);
         break;
 
-    // TODO: move error code simulation to 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);
-                break;
-            case asset_search::not_found:
-            case asset_search::found_deleted:
-                find_replace_all ("$expect", "PSA_ERROR_INVALID_HANDLE",
-                                  check_code);  // TODO:  take from boilerplate
-                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
-                break;
-        }
-        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");
     }
 }
 
@@ -358,7 +401,7 @@
                           asset_search how_asset_found)
                              : psa_call(test_state, call_ser_no, how_asset_found)
 {
-    // Nothing further to initialize.
+    policy = key_policy_info::create_random();
     return;  // just to have something to pin a breakpoint onto
 }
 crypto_call::~crypto_call (void)
diff --git a/tf_fuzz/tfz-cpp/calls/psa_call.hpp b/tf_fuzz/tfz-cpp/calls/psa_call.hpp
index 08d7316..9a497c0 100644
--- a/tf_fuzz/tfz-cpp/calls/psa_call.hpp
+++ b/tf_fuzz/tfz-cpp/calls/psa_call.hpp
@@ -83,6 +83,15 @@
     /// never be overwritten.
     virtual bool simulate (void);
 
+    // Update policy information in the call based on the policy
+    // asset specified in policy.get_policy_from_policy. If this is unset,
+    // the existing values are used as-is.
+    //
+    // This enables the simulation time setting of the policy.
+    //
+    // See `key_policy_info.get_policy_from_policy`.
+    void copy_policy_to_call(void);
+
     // TODO: move simulation and error modelling code code into simulate().
     // once this is done, remove default impl so that simulate is mandatory for
     // calls.
@@ -159,7 +168,8 @@
 public:
     // Data members:  // (low value in hiding these behind setters and getters)
     // Methods:
-        bool copy_asset_to_call (void);
+        bool copy_asset_to_call (void) override;
+        virtual bool simulate() override;
         crypto_call (tf_fuzz_info *test_state, long &asset_ser_no,
                     asset_search how_asset_found);  // (constructor)
         ~crypto_call (void);
@@ -167,12 +177,12 @@
 protected:
     // Data members:
     // Methods:
-        void fill_in_result_code (void);
+        void fill_in_result_code (void) override;
            // for now, the method-overide buck stops here, but that'll probably change
+        bool simulate_ret_code(void);
+
 
 private:
-    // Data members:
-    // Methods:
 };
 
 class security_call : public psa_call
diff --git a/tf_fuzz/tfz-cpp/crypto_model/crypto_model.cpp b/tf_fuzz/tfz-cpp/crypto_model/crypto_model.cpp
new file mode 100644
index 0000000..e6b8caf
--- /dev/null
+++ b/tf_fuzz/tfz-cpp/crypto_model/crypto_model.cpp
@@ -0,0 +1,456 @@
+/* Copyright (c) 2024 Arm Limited. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "crypto_model.hpp"
+#include <algorithm>
+#include <cmath>
+#include <map>
+#include <numeric>
+#include <stdexcept>
+
+using namespace crypto_model;
+using namespace crypto_model::internal;
+using namespace std;
+
+std::map<std::string,crypto_model::key_type> key_types;
+std::map<std::string,crypto_model::algorithm> algorithms;
+std::vector<std::string> hash_algorithms;
+
+// From PSA_VENDOR_RSA_MAX_KEY_BITS
+const uint RSA_KEY_MAX_SIZE = 4096;
+
+// From PSA_VENDOR_RSA_MIN_KEY_BITS
+const uint RSA_KEY_MIN_SIZE = 1024;
+
+// From PSA_MAX_KEY_BITS
+const uint MAX_KEY_SIZE = 0xfff8;
+
+// Size cannot be 0
+const uint MIN_KEY_SIZE = 1;
+
+const std::vector<std::pair<string, string>> key_type_allowed_with_algorithm = {
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CBC_MAC"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CMAC"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CTR"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CFB"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_OFB"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CBC_NO_PADDING"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CBC_PKCS7"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_ECB_NO_PADDING"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_CCM"},
+    {"PSA_KEY_TYPE_AES","PSA_ALG_GCM"},
+
+    {"PSA_KEY_TYPE_ARC4","PSA_ALG_STREAM_CIPHER"},
+
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CBC_MAC"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CMAC"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CTR"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CFB"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_OFB"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CBC_NO_PADDING"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CBC_PKCS7"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_ECB_NO_PADDING"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_CCM"},
+    {"PSA_KEY_TYPE_ARIA","PSA_ALG_GCM"},
+
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CBC_MAC"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CMAC"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CTR"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CFB"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_OFB"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CBC_NO_PADDING"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CBC_PKCS7"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_ECB_NO_PADDING"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_CCM"},
+    {"PSA_KEY_TYPE_CAMELLIA","PSA_ALG_GCM"},
+
+    {"PSA_KEY_TYPE_CHACHA20","PSA_ALG_STREAM_CIPHER"},
+    {"PSA_KEY_TYPE_CHACHA20","PSA_ALG_CHACHA20_POLY1305"},
+
+    {"PSA_KEY_TYPE_DES","PSA_ALG_CMAC"},
+    {"PSA_KEY_TYPE_DES","PSA_ALG_CTR"},
+    {"PSA_KEY_TYPE_DES","PSA_ALG_CFB"},
+    {"PSA_KEY_TYPE_DES","PSA_ALG_OFB"},
+    {"PSA_KEY_TYPE_DES","PSA_ALG_CBC_NO_PADDING"},
+    {"PSA_KEY_TYPE_DES","PSA_ALG_CBC_PKCS7"},
+    {"PSA_KEY_TYPE_DES","PSA_ALG_ECB_NO_PADDING"},
+
+    {"PSA_KEY_TYPE_HMAC","PSA_ALG_HMAC"},
+
+    {"PSA_KEY_TYPE_DERIVE","PSA_ALG_HKDF"},
+    {"PSA_KEY_TYPE_DERIVE","PSA_ALG_TLS12_PRF"},
+    {"PSA_KEY_TYPE_DERIVE","PSA_ALG_TLS12_PSK_TO_MS"},
+
+    {"PSA_KEY_TYPE_PASSWORD_HASH","PSA_ALG_PBKDF2_HMAC"},
+    {"PSA_KEY_TYPE_PASSWORD_HASH","PSA_ALG_PBKDF2_AES_CMAC_PRF_128"},
+
+    {"PSA_KEY_TYPE_PASSWORD","PSA_ALG_PBKDF2_HMAC"},
+    {"PSA_KEY_TYPE_PASSWORD","PSA_ALG_PBKDF2_AES_CMAC_PRF_128"},
+
+    {"PSA_KEY_TYPE_PEPPER","PSA_ALG_PBKDF2_HMAC"},
+    {"PSA_KEY_TYPE_PEPPER","PSA_ALG_PBKDF2_AES_CMAC_PRF_128"},
+
+    {"PSA_KEY_TYPE_RAW_DATA","PSA_ALG_HKDF"},
+    {"PSA_KEY_TYPE_RAW_DATA","PSA_ALG_TLS12_PRF"},
+    {"PSA_KEY_TYPE_RAW_DATA","PSA_ALG_TLS12_PSK_TO_MS"},
+
+    {"PSA_KEY_TYPE_RSA_KEY_PAIR","PSA_ALG_RSA_OAEP"},
+    {"PSA_KEY_TYPE_RSA_KEY_PAIR","PSA_ALG_RSA_PKCS1V15_CRYPT"},
+    {"PSA_KEY_TYPE_RSA_KEY_PAIR","PSA_ALG_RSA_PKCS1V15_SIGN"},
+    {"PSA_KEY_TYPE_RSA_KEY_PAIR","PSA_ALG_RSA_PKCS1V15_SIGN_RAW"},
+
+    {"PSA_KEY_TYPE_RSA_PUBLIC_KEY","PSA_ALG_RSA_OAEP"},
+    {"PSA_KEY_TYPE_RSA_PUBLIC_KEY","PSA_ALG_RSA_PKCS1V15_CRYPT"},
+    {"PSA_KEY_TYPE_RSA_PUBLIC_KEY","PSA_ALG_RSA_PKCS1V15_SIGN"},
+    {"PSA_KEY_TYPE_RSA_PUBLIC_KEY","PSA_ALG_RSA_PKCS1V15_SIGN_RAW"},
+};
+
+// See tf-m/lib/ext/mbed-crypto/mbed_crypto_config
+const std::vector<string> disabled_key_types = {
+    "PSA_KEY_TYPE_ARIA",
+    "PSA_KEY_TYPE_ARC4",
+    "PSA_KEY_TYPE_CAMELLIA",
+    "PSA_KEY_TYPE_CHACHA20",
+    "PSA_KEY_TYPE_DES"
+};
+
+// See tf-m/lib/ext/mbed-crypto/mbed_crypto_config
+const std::vector<string> disabled_algorithms = {
+    "PSA_ALG_CBC_MAC",
+    "PSA_ALG_CHACHA20_POLY1305",
+    "PSA_WANT_ALG_ECB_NO_PADDING",
+    "PSA_ALG_MD5",
+    "PSA_ALG_OFB",
+    "PSA_ALG_SHA_1",
+    "PSA_ALG_PBKDF2_HMAC",
+    "PSA_ALG_RIPEMD160",
+    "PSA_ALG_STREAM_CIPHER",
+};
+
+// for readability
+const bool doesnt_require_hash = false;
+const bool requires_hash = true;
+const bool hash_alg = true;
+const bool not_hash_alg = false;
+
+void crypto_model::init_crypto_model(void) {
+
+    // Key type definitions.
+
+    define_key_type("PSA_KEY_TYPE_AES", {128, 192, 256}, MAX_KEY_SIZE,
+                    MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_ARC4", {},40,2048);
+    define_key_type("PSA_KEY_TYPE_CAMELLIA", {128, 192, 256}, MAX_KEY_SIZE,
+                    MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_CHACHA20", {256}, 256, 256);
+    define_key_type("PSA_KEY_TYPE_DES", {64, 128, 192}, MAX_KEY_SIZE,
+                    MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_DERIVE", {}, MAX_KEY_SIZE, MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_HMAC", {}, MAX_KEY_SIZE, MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_RAW_DATA", {}, MAX_KEY_SIZE, MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_PASSWORD", {}, MAX_KEY_SIZE, MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_PASSWORD_HASH", {}, MAX_KEY_SIZE,
+                    MIN_KEY_SIZE);
+
+    define_key_type("PSA_KEY_TYPE_PEPPER", {}, MAX_KEY_SIZE, MIN_KEY_SIZE);
+    define_key_type("PSA_KEY_TYPE_RSA_KEY_PAIR", {}, RSA_KEY_MAX_SIZE,
+                    RSA_KEY_MIN_SIZE);
+
+    define_key_type("PSA_KEY_TYPE_RSA_PUBLIC_KEY", {}, RSA_KEY_MAX_SIZE,
+                    RSA_KEY_MIN_SIZE);
+
+    // Algorithm definitions
+    define_algorithm("PSA_ALG_CCM",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_GCM",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_CHACHA20_POLY1305",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_RSA_PKCS1V15_CRYPT",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_RSA_OAEP", not_hash_alg, requires_hash);
+    define_algorithm("PSA_ALG_RSA_PKCS1V15_SIGN", not_hash_alg, requires_hash);
+    define_algorithm("PSA_ALG_RSA_PKCS1V15_SIGN_RAW", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_STREAM_CIPHER", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_CTR", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_CCM_STAR_NO_TAG", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_CFB", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_OFB", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_ECB_NO_PADDING", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_CBC_NO_PADDING", not_hash_alg, doesnt_require_hash);
+    define_algorithm("PSA_ALG_CBC_PKCS7", not_hash_alg, doesnt_require_hash);
+
+    define_algorithm("PSA_ALG_MD5",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_RIPEMD160",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_1",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_224",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_256",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_384",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_512",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_512_224",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA_512_256",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA3_224",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA3_256",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA3_384",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA3_512",hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_SHA3_512",hash_alg,doesnt_require_hash);
+
+    define_algorithm("PSA_ALG_FFDH",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_ECDH",not_hash_alg,doesnt_require_hash);
+
+    define_algorithm("PSA_ALG_HKDF",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_TLS12_PRF",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_TLS12_PSK_TO_MS",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_HKDF_EXTRACT",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_HKDF_EXPAND",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_TLS12_ECJPAKE_TO_PMS",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_PBKDF2_HMAC",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_PBKDF2_AES_CMAC_PRF_128",not_hash_alg,doesnt_require_hash);
+
+    define_algorithm("PSA_ALG_HMAC",not_hash_alg,requires_hash);
+    define_algorithm("PSA_ALG_CBC_MAC",not_hash_alg,doesnt_require_hash);
+    define_algorithm("PSA_ALG_CMAC",not_hash_alg,doesnt_require_hash);
+
+    // Load the data tables into the right places
+    for (auto &kt: disabled_key_types) {
+        key_types[kt].enabled = false;
+    }
+
+    for (auto &alg: disabled_algorithms) {
+        algorithms[alg].enabled = false;
+    }
+
+    for (auto pair: key_type_allowed_with_algorithm) {
+        key_type &kt = key_types[pair.first];
+        algorithm &alg = algorithms[pair.second];
+
+        if (!kt.is_enabled() || !alg.is_enabled()) {
+            continue;
+        }
+
+        alg.allowed_key_types.push_back(kt.get_string());
+        kt.allowed_algorithms.push_back(alg.get_string());
+    }
+
+}
+
+void crypto_model::internal::define_key_type(
+    std::string name, std::vector<uint> allowed_key_sizes_bits,
+    uint max_key_size_bits, uint min_key_size_bits) {
+
+    key_type kt;
+    kt.name = name;
+    kt.allowed_key_sizes_bits = allowed_key_sizes_bits;
+    kt.max_key_size_bits = max_key_size_bits;
+    kt.min_key_size_bits = min_key_size_bits;
+
+    key_types[name] = kt;
+}
+
+void crypto_model::internal::define_algorithm(std::string name,
+                                              bool is_hash_algorithm,
+                                              bool requires_hash) {
+    algorithm a;
+    a.name = name;
+    a.is_hash_algorithm_flag = is_hash_algorithm;
+    a.requires_hash_flag = requires_hash;
+
+    if (is_hash_algorithm) {
+        hash_algorithms.push_back(name);
+    }
+
+    algorithms[name] = a;
+}
+
+namespace crypto_model {
+
+uint get_random_key_size() {
+    int lower = std::floor(MIN_KEY_SIZE/ 8);
+    int higher = std::floor(MAX_KEY_SIZE/8);
+    return ((rand() % (higher - lower)) + lower) * 8;
+}
+
+algorithm& get_algorithm(std::string name) {
+
+    // turn hash algs of form PSA_ALG_FOO(PSA_ALG_BAR) into PSA_ALG_FOO.
+    int index = name.find("(");
+    if (index != string::npos) {
+        name = name.substr(index);
+    }
+
+    return algorithms[name];
+}
+
+
+key_type& get_key_type(std::string name) {
+    return key_types[name];
+}
+
+algorithm& get_random_algorithm() {
+    // to randomise:
+    //  get random index.
+    //  if it is a disabled alg, repeat
+    std::vector<int> v(algorithms.size());
+    std::iota(v.begin(),v.end(),0);
+    std::random_shuffle(v.begin(),v.end());
+    auto it = algorithms.begin();
+    for (int i:v) {
+        auto it = algorithms.begin();
+        std::advance(it,i);
+        algorithm& alg = it->second;
+        if (alg.is_enabled()) {
+            return alg;
+        }
+    }
+    throw std::logic_error("No enabled algorithms");
+}
+
+key_type& get_random_key_type() {
+    // to randomise:
+    //  get random index.
+    //  if it is a disabled key type, repeat
+    std::vector<int> v(key_types.size());
+    std::iota(v.begin(),v.end(),0);
+    std::random_shuffle(v.begin(),v.end());
+    auto it = key_types.begin();
+    for (int i:v) {
+        auto it = key_types.begin();
+        std::advance(it,i);
+        key_type& kt = it->second;
+        if (kt.is_enabled()) {
+            return kt;
+        }
+    }
+    throw std::logic_error("No enabled key types");
+}
+
+algorithm& get_random_hash_algorithm() {
+    std::random_shuffle(hash_algorithms.begin(),hash_algorithms.end());
+    for (int i=0;i<hash_algorithms.size();i++) {
+        if (algorithms[hash_algorithms[i]].is_enabled()) {
+            return algorithms[hash_algorithms[i]];
+        }
+    }
+
+    throw std::logic_error("No enabled hash algorithms");
+}
+
+algorithm::algorithm() {
+
+};
+
+algorithm::~algorithm() {
+
+};
+
+string algorithm::get_string() {
+    return name;
+};
+
+bool algorithm::is_enabled() {
+    return enabled;
+}
+
+std::string algorithm::get_string_with_hash() {
+    string out = name;
+    if (requires_hash()) {
+        algorithm& hash_alg = get_random_hash_algorithm();
+        out += "(";
+        out += hash_alg.name;
+        out += ")";
+    }
+
+    return out;
+}
+
+bool algorithm::valid_for_key_type(key_type& kt) {
+    if (std::find(allowed_key_types.begin(),allowed_key_types.end(),kt.get_string()) != allowed_key_types.end()) {
+        return true;
+    }
+    return false;
+}
+
+bool algorithm::requires_hash() {
+    return requires_hash_flag;
+}
+
+bool algorithm::is_hash_algorithm() {
+    return is_hash_algorithm_flag;
+}
+
+key_type& algorithm::random_valid_key_type() {
+    if (allowed_key_types.size() == 0) {
+        throw std::logic_error("No allowed key types for algorithm");
+    }
+    std::random_shuffle(allowed_key_types.begin(),allowed_key_types.end());
+    return key_types[allowed_key_types[0]];
+
+}
+key_type::key_type() {
+
+};
+
+key_type::~key_type() {
+
+};
+
+string key_type::get_string() {
+    return name;
+}
+
+bool key_type::is_enabled() {
+    return enabled;
+}
+
+algorithm& key_type::random_allowed_algorithm() {
+    if (allowed_algorithms.size() == 0) {
+        throw std::logic_error("Key type has no allowed algorithms");
+    }
+    std::random_shuffle(allowed_algorithms.begin(),allowed_algorithms.end());
+    return algorithms[allowed_algorithms[0]];
+
+}
+
+bool key_type::is_allowed_algorithm(algorithm& algorithm) {
+    if (std::find(allowed_algorithms.begin(),allowed_algorithms.end(),algorithm.get_string()) != allowed_algorithms.end()) {
+        return true;
+    }
+    return false;
+}
+
+bool key_type::is_valid_key_size(uint size) {
+    // (MbedTLS): size is always byte aligned
+    if (size % 8 != 0) {
+        return false;
+    }
+
+    if (size > max_key_size_bits) {
+        return false;
+    }
+
+    if (size < min_key_size_bits) {
+        return false;
+    }
+
+    // some keys only allow a fixed set of values
+    if (!allowed_key_sizes_bits.empty()) {
+        if (std::find(allowed_key_sizes_bits.begin(),
+                      allowed_key_sizes_bits.end(),
+                      size) == allowed_key_sizes_bits.end()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+uint key_type::get_random_valid_key_size() {
+    if (!allowed_key_sizes_bits.empty()) {
+        std::random_shuffle(allowed_key_sizes_bits.begin(),allowed_key_sizes_bits.end());
+        return allowed_key_sizes_bits[0];
+    }
+
+    int lower = floor(min_key_size_bits/ 8);
+    int higher = floor(max_key_size_bits/8);
+
+    return ((rand() % (higher - lower)) + lower) * 8;
+}
+
+} // namespace crypto_model
diff --git a/tf_fuzz/tfz-cpp/crypto_model/crypto_model.hpp b/tf_fuzz/tfz-cpp/crypto_model/crypto_model.hpp
new file mode 100644
index 0000000..0d3bf92
--- /dev/null
+++ b/tf_fuzz/tfz-cpp/crypto_model/crypto_model.hpp
@@ -0,0 +1,100 @@
+/* Copyright (c) 2024 Arm Limited. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// crypto_model.hpp
+#pragma once
+
+#include <string>
+#include <vector>
+#include "crypto_model_internal.hpp"
+
+/*
+ * `crypto_model` contains information about crypto key types, algorithms, and
+ * attributes, and their compatabilities with each-other.
+ */
+namespace crypto_model {
+
+// forward declarations
+class key_type;
+class algorithm;
+
+algorithm& get_algorithm(std::string);
+key_type& get_key_type(std::string);
+
+algorithm& get_random_hash_algorithm();
+
+algorithm& get_random_algorithm();
+
+key_type& get_random_key_type();
+
+uint get_random_key_size();
+
+//! Initialises the crypto model.
+void init_crypto_model();
+
+
+// Classes to hold data.
+class algorithm {
+    friend void crypto_model::init_crypto_model();
+    friend void crypto_model::internal::define_algorithm(std::string,bool,bool);
+
+public:
+    algorithm();
+    ~algorithm();
+
+    std::string get_string();
+
+    // Gets the header value form of the algorithm, with a random hash function
+    // filled in if needed.
+    std::string get_string_with_hash();
+    bool is_enabled();
+
+    bool is_hash_algorithm();
+    bool requires_hash();
+
+    bool valid_for_key_type(key_type&);
+    key_type& random_valid_key_type();
+
+private:
+
+    std::string name;
+    std::vector<std::string> allowed_key_types;
+    bool requires_hash_flag;
+    bool is_hash_algorithm_flag;
+    bool enabled=true;
+};
+
+class key_type {
+    friend void crypto_model::init_crypto_model();
+    friend void crypto_model::internal::define_key_type(std::string, std::vector<uint>, uint, uint);
+
+public:
+    key_type();
+    ~key_type();
+
+    std::string get_string();
+    bool is_enabled();
+
+    bool is_allowed_algorithm(algorithm&);
+    algorithm& random_allowed_algorithm();
+    bool is_valid_key_size(uint size);
+    uint get_random_valid_key_size();
+
+
+private:
+
+    std::string name;
+
+    // If non empty, the key size must be one of the values in this vector.
+    std::vector<uint> allowed_key_sizes_bits;
+    uint max_key_size_bits;
+    uint min_key_size_bits;
+
+    std::vector<std::string> allowed_algorithms;
+
+    bool enabled=true;
+};
+
+} // namespace crypto_model
diff --git a/tf_fuzz/tfz-cpp/crypto_model/crypto_model_internal.hpp b/tf_fuzz/tfz-cpp/crypto_model/crypto_model_internal.hpp
new file mode 100644
index 0000000..93a6fc9
--- /dev/null
+++ b/tf_fuzz/tfz-cpp/crypto_model/crypto_model_internal.hpp
@@ -0,0 +1,30 @@
+/* Copyright (c) 2024 Arm Limited. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// crypto_model_internal.hpp
+#pragma once
+
+/* Internal functions for the crypto model */
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace crypto_model {
+class key_type;
+class algorithm;
+}
+
+namespace crypto_model::internal {
+
+    // helper functions for init_crypto_model
+    // these are in the header file so that they can be declared as friends.
+    void define_algorithm(std::string name, bool is_hash_algorithm,
+                          bool requires_hash);
+
+    void define_key_type(std::string name,
+                         std::vector<uint> allowed_key_sizes_bits,
+                         uint max_key_size_bits, uint min_key_size_bits);
+}
diff --git a/tf_fuzz/tfz-cpp/crypto_model/fill_in_policy.cpp b/tf_fuzz/tfz-cpp/crypto_model/fill_in_policy.cpp
new file mode 100644
index 0000000..306d93a
--- /dev/null
+++ b/tf_fuzz/tfz-cpp/crypto_model/fill_in_policy.cpp
@@ -0,0 +1,72 @@
+/*  Copyright (c) 2024 Arm Limited. All Rights Reserved.
+ *
+ *  SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <cstring>
+#include <string>
+
+#include "fill_in_policy.hpp"
+#include "crypto_model.hpp"
+
+void fill_in_policy(key_policy_info &policy_info, bool policy_must_be_valid) {
+
+  // for set key <NAME> policy <POLICY> calls, we want to model based on the
+  // policy asset given.
+
+  // in this scenario, the policy cant be filled out now, and the information
+  // should be copied over later.
+  if (!policy_info.get_policy_from_policy.empty()) {
+        return;
+  }
+
+  if (policy_must_be_valid) {
+
+        crypto_model::key_type& kt = crypto_model::get_random_key_type();
+        if (policy_info.key_type.empty() && policy_info.key_algorithm.empty()) {
+            policy_info.key_type = kt.get_string();
+            policy_info.key_algorithm = kt.random_allowed_algorithm().get_string_with_hash();
+
+        } else if (policy_info.key_algorithm.empty() && !policy_info.key_type.empty()) {
+            kt = crypto_model::get_key_type(policy_info.key_type);
+            policy_info.key_algorithm = kt.random_allowed_algorithm().get_string_with_hash();
+
+        } else if (policy_info.key_type.empty() && !policy_info.key_algorithm.empty()) {
+            crypto_model::algorithm& alg = crypto_model::get_algorithm(policy_info.key_algorithm);
+            kt = alg.random_valid_key_type();
+            policy_info.key_type = kt.get_string();
+        }
+
+        if (policy_info.n_bits == 0) {
+            policy_info.n_bits = kt.get_random_valid_key_size();
+        }
+
+    } else {
+        if (policy_info.key_type.empty()) {
+            policy_info.key_type = crypto_model::get_random_key_type().get_string();
+        }
+
+        if (policy_info.key_algorithm.empty()) {
+            policy_info.key_algorithm= crypto_model::get_random_algorithm().get_string_with_hash();
+        }
+
+        if (policy_info.n_bits == 0) {
+            policy_info.n_bits = crypto_model::get_random_key_size();
+        }
+    }
+
+    // randomise usage flags and persistence if they arn't explicitly turned on or off.
+    if (!policy_info.exportable && !policy_info.no_exportable) policy_info.exportable= (rand() % 2);
+    if (!policy_info.copyable && !policy_info.no_copyable) policy_info.copyable= (rand() %2);
+    if (!policy_info.can_encrypt && !policy_info.no_can_encrypt) policy_info.can_encrypt= (rand() %2);
+    if (!policy_info.can_decrypt && !policy_info.no_can_decrypt) policy_info.can_decrypt= (rand() %2);
+    if (!policy_info.can_verify && !policy_info.no_can_verify) policy_info.can_verify= (rand() % 2);
+    if (!policy_info.can_sign && !policy_info.no_can_sign) policy_info.can_sign= (rand() %2);
+    if (!policy_info.derivable && !policy_info.no_derivable) policy_info.derivable= (rand() %2);
+
+    // TODO: persistence seems to be a little bit broken, so disable for now..
+
+    // if (!policy_info.persistent && !policy_info.no_persistent) policy_info.persistent= (rand() %2);
+
+}
diff --git a/tf_fuzz/tfz-cpp/crypto_model/fill_in_policy.hpp b/tf_fuzz/tfz-cpp/crypto_model/fill_in_policy.hpp
new file mode 100644
index 0000000..43e4963
--- /dev/null
+++ b/tf_fuzz/tfz-cpp/crypto_model/fill_in_policy.hpp
@@ -0,0 +1,30 @@
+/*  Copyright (c) 2024 Arm Limited. All Rights Reserved.
+ *
+ *  SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FILL_IN_POLICY_HPP
+#define FILL_IN_POLICY_HPP
+
+#include "data_blocks.hpp"
+
+/** Fill in all blank fields of policy_info with random values.
+ *
+ * If policy_must_be_valid is true, random valid values will be given, and
+ * TF-Fuzz will error if there is no satisfying values for the policy.
+ *
+ * For a policy to be valid:
+ *
+ *  * The key type and algorithm are not disabled.
+ *  * The key type and algorithm are compatible with eachother.
+ *  * The key size is compatible with the key size.
+ *
+ * This is more stringent than the requirements of psa_generate_key(), which
+ * does not require that the key type and algorithm are compatible. However, a
+ * policy of this kind is functionally useless, so to improve test usefulness,
+ * this requirement is enforced here anyways.
+ *
+ */
+void fill_in_policy(key_policy_info &policy_info, bool policy_must_be_valid);
+
+#endif // FILL_IN_POLICY_HPP
diff --git a/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.l b/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.l
index 429e60c..7df9896 100644
--- a/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.l
+++ b/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.l
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -151,6 +151,7 @@
 vol                       return VOLATILE;
 from                      return FROM;
 with                      return WITH;
+valid                     return VALID;
   /* Structure operands: */
 [a-zA-z][a-zA-Z_0-9]*     {yylval.str = yytext; return IDENTIFIER_TOK;}
 [+-]?[0-9]*               {yylval.valueN = atol(yytext); return NUMBER_TOK;}
@@ -162,4 +163,3 @@
 .                         yyerror ((tf_fuzz_info *) NULL, "Unexpected character");
 
 %%
-
diff --git a/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.y b/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.y
index 4782d0c..dae9c7d 100644
--- a/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.y
+++ b/tf_fuzz/tfz-cpp/parser/tf_fuzz_grammar.y
@@ -29,6 +29,7 @@
 #include "secure_template_line.hpp"
 #include "sst_template_line.hpp"
 #include "crypto_template_line.hpp"
+#include "fill_in_policy.hpp"
 
 /* These items are defined in tf_fuzz_grammar.l.  Note, however that, because
    of "name mangling," defining them as extern "C" may or may not be ideal,
@@ -133,6 +134,8 @@
 bool literal_is_string = true;
     /* if true, literal value is character-string;  if false, is list of hex values */
 
+bool policy_must_be_valid = false;
+
 /* The following are more tied to the template syntax than to the resulting PSA calls */
 string literal;  /* temporary holder for all string literals */
 string identifier;  /* temporary holder for strings representing identifiers */
@@ -269,12 +272,20 @@
     bool create_call_bool,  /* true to create the PSA call at this time */
     bool create_asset_bool,  /* true to create the PSA asset at this time */
     bool fill_in_template,  /* true to back-fill info into template */
-    int instance
+    int instance,
         /* if further differentiation to the names or IDs is needed, make instance >0 */
+    bool do_fill_in_policy=false,
+    bool policy_must_be_valid=false
 ) {
     const bool yes_fill_in_template = true;  /* just to improve readability */
     vector<psa_asset*>::iterator t_psa_asset;
 
+    // take the partial policy info specified by the user, and flesh it out
+    // into either a random policy, or a random valid policy.
+    if (do_fill_in_policy) {
+        fill_in_policy(policy_info,policy_must_be_valid);
+    }
+
     if (fill_in_template) {
         /* Set basic parameters from the template line: */
         templateLin->set_data = set_data;
@@ -361,6 +372,7 @@
 %token <valueN> NUMBER_TOK  /* variables and content */
 %token <tokenN> SEMICOLON SHUFFLE TO OF OPEN_BRACE CLOSE_BRACE  /* block structure */
 %token <tokenN> ATTR TYPE ALG  /* "set policy" line portions */
+%token <tokenN> VALID
 %token <tokenN> EXPORT COPY ENCRYPT DECRYPT SIGN VERIFY DERIVE  /* key-usage keywords */
 %token <tokenN> NOEXPORT NOCOPY NOENCRYPT NODECRYPT NOSIGN NOVERIFY NODERIVE
 %token <tokenN> PERSISTENT VOLATILE  /* key lifetime keywords */
@@ -382,6 +394,8 @@
             expect = expect_info();
             set_data = set_data_info();
             parsed_asset = asset_name_id_info();
+
+            // blank new policy -- this is filled in later by interpret template
             policy_info = key_policy_info();
         }
       ;
@@ -403,10 +417,16 @@
             expect = expect_info();
             set_data = set_data_info();
             parsed_asset = asset_name_id_info();
+
+            // blank new policy -- this is filled in later by interpret template
             policy_info = key_policy_info();
+            policy_must_be_valid = false;
+
             target_barrier = "";
         }
       | block {
+            policy_info = key_policy_info();
+            policy_must_be_valid = false;
             /* TODO:  This code may not won't work with "secure hash neq ..." */
             IVM(cout << "Block of lines." << endl;)
             /* "Statisticalize" :-) the vector of template lines, then crank
@@ -430,6 +450,7 @@
                     yes_create_asset,
                     dont_fill_in_template,  /* but did fill it all in before */
                     0
+
                 );
                 k++;
                 for (add_expect = 0;  add_expect < rsrc->calls.size();  ++add_expect) {
@@ -438,7 +459,7 @@
                         templateLin->expect.expected_results_saved = true;
                     }
                 }
-            }
+    }
             templateLin->asset_info.asset_id_n_vector.clear();
             templateLin->asset_info.asset_name_vector.clear();
             /* Done.  Empty out the "statisticalization" vector: */
@@ -449,6 +470,8 @@
             IVM(cout << "Finished coding block of lines." << endl;)
         }
       | command SEMICOLON {
+            policy_info = key_policy_info();
+            policy_must_be_valid = false;
             IVM(cout << "Command with no expect:  \"" << flush;)
             if (!purpose_defined) {
                 cerr << endl << endl
@@ -473,6 +496,8 @@
             IVM(cout << yytext << "\"" << endl;)
         }
       | command expect SEMICOLON {
+            policy_info = key_policy_info();
+            policy_must_be_valid = false;
             /* (This is the same as for command SEMICOLON, other than the IVM.) */
             IVM(cout << "Command with expect:  \"" << flush;)
             if (!purpose_defined) {
@@ -562,10 +587,12 @@
                 print_data, hash_data, asset_name, assign_data_var, parsed_asset,
                 nesting_level == 0 /* create call unless inside {} */,
                 nesting_level == 0 /* similarly, create asset unless inside {} */,
-                yes_fill_in_template, 0
+                yes_fill_in_template, 0,
+                true,
+                policy_must_be_valid
             );
         }
-      | SET POLICY policy_set_args {
+      | SET POLICY policy_set_args policy_valid{
             IVM(cout << "Set policy command:  \"" << yytext << "\"" << endl;;)
             templateLin = new set_policy_template_line (rsrc);
             interpret_template_line (
@@ -574,7 +601,9 @@
                 print_data, hash_data, asset_name, assign_data_var, parsed_asset,
                 nesting_level == 0 /* create call unless inside {} */,
                 nesting_level == 0 /* similarly, create asset unless inside {} */,
-                yes_fill_in_template, 0
+                yes_fill_in_template, 0,
+                true,
+                policy_must_be_valid
             );
         }
       ;
@@ -988,7 +1017,7 @@
       ;
 
 noexport : NOEXPORT {
-            policy_info.exportable = false;
+            policy_info.no_exportable = true;
             IVM(cout << "Non-exportable key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1000,7 +1029,7 @@
       ;
 
 nocopy : NOCOPY {
-            policy_info.copyable = false;
+            policy_info.no_copyable = true;
             IVM(cout << "Non-copyable key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1012,7 +1041,7 @@
       ;
 
 noencrypt : NOENCRYPT {
-            policy_info.can_encrypt = false;
+            policy_info.no_can_encrypt = true;
             IVM(cout << "Non-encryption key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1024,7 +1053,7 @@
       ;
 
 nodecrypt : NODECRYPT {
-            policy_info.can_decrypt = false;
+            policy_info.no_can_decrypt = true;
             IVM(cout << "Non-decryption key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1036,7 +1065,7 @@
       ;
 
 nosign : NOSIGN {
-            policy_info.can_sign = false;
+            policy_info.no_can_sign = true;
             IVM(cout << "Non-signing key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1048,7 +1077,7 @@
       ;
 
 noverify : NOVERIFY {
-            policy_info.can_verify = false;
+            policy_info.no_can_verify = true;
             IVM(cout << "Non-verify key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1060,7 +1089,7 @@
       ;
 
 noderive : NODERIVE {
-            policy_info.derivable = false;
+            policy_info.no_derivable = true;
             IVM(cout << "Non-derivable key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1072,7 +1101,7 @@
       ;
 
 volatle : VOLATILE {
-            policy_info.persistent = false;
+            policy_info.no_persistent = true;
             IVM(cout << "Volatile key:  " << yytext << "\"" << endl;)
         }
       ;
@@ -1118,7 +1147,7 @@
       | NAME ASSET_IDENTIFIER_LIST {
             IVM(cout << "policy-asset identifier list:  \"" << flush;)
             random_name = false;
-            asset_name.assign (identifier);  /* TODO:  Not sure this ultimately has any effect... */
+            asset_name = identifier;  /* TODO:  Not sure this ultimately has any effect... */
             random_asset = psa_asset_usage::all;  /* don't randomly choose existing asset */
             parsed_asset.id_n_not_name = false;
             IVM(cout << yytext << "\"" << endl;)
@@ -1141,7 +1170,7 @@
             IVM(cout << "policy-asset identifier list:  \"" << flush;)
             random_name = false;
             policy_info.get_policy_from_key = false;
-            asset_name.assign (identifier);  /* TODO:  Not sure this ultimately has any effect... */
+            asset_name = identifier;  /* TODO:  Not sure this ultimately has any effect... */
             parsed_asset.asset_name_vector.push_back (identifier);
             random_asset = psa_asset_usage::all;  /* don't randomly choose existing asset */
             parsed_asset.id_n_not_name = false;
@@ -1178,6 +1207,15 @@
         }
       ;
 
+policy_valid:
+        %empty /* nothing */ {
+            policy_must_be_valid = false;
+        }
+        | VALID /* policy must be valid */ {
+            IVM(cout << "Policy-create must be valid" << endl;)
+            policy_must_be_valid = true;
+
+        }
 policy_read_args:
         policy_asset_name read_args {
             IVM(cout << "Policy-read arguments:  " << yytext << "\"" << endl;)
@@ -1200,6 +1238,7 @@
       | POLICY IDENTIFIER {
             IVM(cout << "Key-set sources, explicitly-specified policy name:  "
                      << flush;)
+            policy_info.get_policy_from_policy = identifier;
             policy_info.asset_2_name = identifier;  /* policy */
             /* Make note that key data (key material) was not specified: */
             IVM(cout << yytext << "\"" << endl;)
diff --git a/tf_fuzz/tfz-cpp/tf_fuzz.cpp b/tf_fuzz/tfz-cpp/tf_fuzz.cpp
index 4be4a1d..f11c29d 100644
--- a/tf_fuzz/tfz-cpp/tf_fuzz.cpp
+++ b/tf_fuzz/tfz-cpp/tf_fuzz.cpp
@@ -24,6 +24,7 @@
 #include "psa_call.hpp"
 #include "tf_fuzz_grammar.tab.hpp"
 #include "variables.hpp"
+#include "crypto_model.hpp"
 
 
 extern FILE* yyin;  // telling lex&yacc which file to parse
@@ -253,6 +254,7 @@
         IV(cout << "    " << this_call->call_description << " for asset "
                 << this_call->asset_info.get_name() << endl;)
 
+        this_call->copy_policy_to_call();
         this_call->simulate();
         this_call->copy_call_to_asset();
            /* Note:  this_call->the_asset will now point to the asset
@@ -493,6 +495,8 @@
     // Allocate "the world":
     tf_fuzz_info *rsrc = new tf_fuzz_info;
 
+    crypto_model::init_crypto_model();
+
     // Parse parameters and open files:
     rsrc->parse_cmd_line_params (argc, argv);
 
diff --git a/tf_fuzz/tfz-cpp/utility/data_blocks.cpp b/tf_fuzz/tfz-cpp/utility/data_blocks.cpp
index 5683b06..d80d46f 100644
--- a/tf_fuzz/tfz-cpp/utility/data_blocks.cpp
+++ b/tf_fuzz/tfz-cpp/utility/data_blocks.cpp
@@ -15,7 +15,7 @@
 #include <vector>
 #include <iostream>
 
-#include "randomization.hpp"
+#include "fill_in_policy.hpp"
 #include "gibberish.hpp"
 #include "data_blocks.hpp"
 #include "find_or_create_asset.hpp"
@@ -359,25 +359,24 @@
 {
     get_policy_from_key = false;  // specify policy asset by a key that uses it.
     copy_key = false;  // not copying one key to another
-    /* The following settings are not necessarily being randomized in mutually-
-       consistent ways, for two reasons:  First, the template should set all that
-       matter, and second, testing TF response to nonsensical settings is also
-       valuable. */
-    exportable  = (rand()%2==1? true : false);
-    copyable    = (rand()%2==1? true : false);
-    can_encrypt = (rand()%2==1? true : false);
-    can_decrypt = (rand()%2==1? true : false);
-    can_sign    = (rand()%2==1? true : false);
-    can_verify  = (rand()%2==1? true : false);
-    derivable   = (rand()%2==1? true : false);
-    persistent  = (rand()%2==1? true : false);
-    // There's a really huge number of possible key types; won't randomize all:
-    key_type = rand_key_type();
+    exportable = false;
+    copyable = false;
+    can_encrypt = false;
+    can_decrypt = false;
+    can_sign = false;
+    can_verify = false;
+    derivable= false;
+    persistent= false;
+
+    get_policy_from_policy = "";
+    key_type = "";
+    key_algorithm = "";
+    n_bits = 0;
+
     usage_string.assign ("");
     print_usage_true_string.assign ("");
     print_usage_false_string.assign ("");
-    key_algorithm = rand_key_algorithm();
-    n_bits = 55 + (rand() % 1000);
+
     gibberish *gib = new gibberish;
     char buffer[256];
     char *end;
@@ -389,7 +388,15 @@
     gib->sentence (buffer, buffer + (40ULL + (uint64_t) (rand() % 200)));
     key_data = buffer;
     delete gib;
+
 }
+
+key_policy_info key_policy_info::create_random() {
+    key_policy_info policy;
+    fill_in_policy(policy,false);
+    return policy;
+}
+
 key_policy_info::~key_policy_info (void)  // (destructor)
 {
     return;  // (even if only to have something to pin a breakpoint on)
diff --git a/tf_fuzz/tfz-cpp/utility/data_blocks.hpp b/tf_fuzz/tfz-cpp/utility/data_blocks.hpp
index 9f6cfc2..03b1294 100644
--- a/tf_fuzz/tfz-cpp/utility/data_blocks.hpp
+++ b/tf_fuzz/tfz-cpp/utility/data_blocks.hpp
@@ -213,21 +213,46 @@
 public:
     // Data members:
     // Digested info:
-    bool get_policy_from_key;
     /* if true, then we must get policy info from a stated key;  the asset
-               here is a key that uses the policy, and not the policy itself. */
-    bool implicit_policy;
+      here is a key that uses the policy, and not the policy itself. */
+    bool get_policy_from_key;
+
+    // If set, the policy asset specified should be used to fill in the policy
+    // at simulation time. This overwrites the other values in the object.
+    //
+    // If blank, the values in the object are used as-is.
+    //
+    // See `psa_call::copy_policy_to_call`
+    string get_policy_from_policy;
+
     /* if true, then the key was defined with policy specifications, but not
-               a named policy, meaning that we have to create an implicit policy. */
-    bool copy_key;  // true to indicate copying one key to another
-    bool exportable;   // key data can be exported (viewed - fail exports if not).
-    bool copyable;     // can be copied (fail key-copies if not).
-    bool can_encrypt;  // OK for encryption (fail other uses).
-    bool can_decrypt;  // OK for decryption (fail other uses).
-    bool can_sign;     // OK for signing (fail other operations).
-    bool can_verify;   // OK for verifying a message signature (fail other uses).
-    bool derivable;    // OK for derive other keys (fail other uses).
-    bool persistent;   // must be deleted at the end of test.
+     a named policy, meaning that we have to create an implicit policy. */
+    bool implicit_policy;
+    bool copy_key = false;  // true to indicate copying one key to another
+    bool exportable=false;   // key data can be exported (viewed - fail exports if not).
+    bool copyable=false;     // can be copied (fail key-copies if not).
+    bool can_encrypt=false;  // OK for encryption (fail other uses).
+    bool can_decrypt=false;  // OK for decryption (fail other uses).
+    bool can_sign=false;     // OK for signing (fail other operations).
+    bool can_verify=false;   // OK for verifying a message signature (fail other uses).
+    bool derivable=false;    // OK for derive other keys (fail other uses).
+    bool persistent=false;   // must be deleted at the end of test.
+
+
+    // no_<flag> denotes that <flag> must not be set in the key.
+    //
+    // For the above flags, truth means "must be set" and false means "don't care".
+    // Setting no_<flag> means "must not be set". no_<flag> takes presedence over <flag>.
+
+    bool no_exportable=false; // true to indicate that exportable must not be set during randomisation
+    bool no_copyable=false; // true to indicate that copyable must not be set during randomisation
+    bool no_can_encrypt=false; // true to indicate that can_encrypt must not be set during randomisation
+    bool no_can_decrypt=false; // true to indicate that can_decrypt must not be set during randomisation
+    bool no_can_sign=false; // true to indicate that can_sign must not be set during randomisation
+    bool no_can_verify=false; // true to indicate that can_verify must not be set during randomisation
+    bool no_derivable=false; // true to indicate that derivable must not be set during randomisation
+    bool no_persistent=false; // true to indicate that persistent must not be set during randomisation
+
     string usage_string;
     /* This string is set to a PSA_KEY_USAGE_* value in the template
                immediately prior to making define_call<add_policy_usage_call>.
@@ -258,7 +283,16 @@
     ~key_policy_info (void);  // (destructor)
 
 
+    /** Creates a random, but not necessarily valid, policy */
+    static key_policy_info create_random();
+
+
 protected:
+
+    /* The following settings are not necessarily being randomized in mutually-
+       consistent ways, for two reasons:  First, the template should set all that
+       matter, and second, testing TF response to nonsensical settings is also
+       valuable. */
     // Data members:
     bool data_matches_asset;
     /* true if template specifies expected data, and that expected data
diff --git a/tf_fuzz/tfz-cpp/utility/randomization.cpp b/tf_fuzz/tfz-cpp/utility/randomization.cpp
deleted file mode 100644
index ded87bb..0000000
--- a/tf_fuzz/tfz-cpp/utility/randomization.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2019-2024, 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.
-**********************************************************************************/
-
-// TODO: the key usages, algorithms, and types are currently incomplete.
-
-#include "randomization.hpp"
-
-#include <stdlib.h>
-
-/**
- * \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_HASH";
-        case 4:  return "PSA_KEY_USAGE_VERIFY_HASH";
-        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() % 24) {
-        case 0:  return "PSA_ALG_MD5";
-        case 1:  return "PSA_ALG_RIPEMD160";
-        case 2:  return "PSA_ALG_SHA_1";
-        case 3:  return "PSA_ALG_SHA_224";
-        case 4:  return "PSA_ALG_SHA_256";
-        case 5:  return "PSA_ALG_SHA_384";
-        case 6:  return "PSA_ALG_SHA_512";
-        case 7:  return "PSA_ALG_SHA_512_224";
-        case 8:  return "PSA_ALG_SHA_512_256";
-        case 9:  return "PSA_ALG_SHA3_224";
-        case 10:  return "PSA_ALG_SHA3_256";
-        case 11:  return "PSA_ALG_SHA3_384";
-        case 12:  return "PSA_ALG_SHA3_512";
-        case 13:  return "PSA_ALG_ANY_HASH";
-        case 14:  return "PSA_ALG_CBC_MAC";
-        case 15:  return "PSA_ALG_CMAC";
-        case 16:  return "PSA_ALG_CTR";
-        case 17:  return "PSA_ALG_CFB";
-        case 18:  return "PSA_ALG_OFB";
-        case 19:  return "PSA_ALG_XTS";
-        case 20:  return "PSA_ALG_CBC_NO_PADDING";
-        case 21:  return "PSA_ALG_CBC_PKCS7";
-        case 22:  return "PSA_ALG_CCM";
-        case 23:  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() % 9) {
-        case 0:  return "PSA_KEY_TYPE_NONE";
-        case 1:  return "PSA_KEY_TYPE_RAW_DATA";
-        case 2:  return "PSA_KEY_TYPE_HMAC";
-        case 3:  return "PSA_KEY_TYPE_DERIVE";
-        case 4:  return "PSA_KEY_TYPE_AES";
-        case 5:  return "PSA_KEY_TYPE_DES";
-        case 6:  return "PSA_KEY_TYPE_CAMELLIA";
-        case 7:  return "PSA_KEY_TYPE_RSA_PUBLIC_KEY";
-        case 8:  return "PSA_KEY_TYPE_RSA_KEY_PAIR";
-    }
-    return "";  /* placate compiler */
-}
diff --git a/tf_fuzz/tfz-cpp/utility/randomization.hpp b/tf_fuzz/tfz-cpp/utility/randomization.hpp
deleted file mode 100644
index b47742a..0000000
--- a/tf_fuzz/tfz-cpp/utility/randomization.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2019-2024, 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 */