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/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;)