If none of the inputs to a key derivation is a
PSA_KEY_DERIVATION_INPUT_SECRET passed with
psa_key_derivation_input_key(), forbid
psa_key_derivation_output_key(). It usually doesn't make sense to
derive a key object if the secret isn't itself a proper key.
After passing some inputs, try getting one byte of output, just to
check that this succeeds (for a valid sequence of inputs) or fails
with BAD_STATE (for an invalid sequence of inputs). Either output a
1-byte key or a 1-byte buffer depending on the test data.
The test data was expanded as follows:
* Output key type (or not a key): same as the SECRET input if success
is expected, otherwise NONE.
* Expected status: PSA_SUCCESS after valid inputs, BAD_STATE after any
invalid input.
Allow a direct input as the SECRET input step in a key derivation, in
addition to allowing DERIVE keys. This makes it easier for
applications to run a key derivation where the "secret" input is
obtained from somewhere else. This makes it possible for the "secret"
input to be empty (keys cannot be empty), which some protocols do (for
example the IV derivation in EAP-TLS).
Conversely, allow a RAW_DATA key as the INFO/LABEL/SALT/SEED input to a key
derivation, in addition to allowing direct inputs. This doesn't
improve security, but removes a step when a personalization parameter
is stored in the key store, and allows this personalization parameter
to remain opaque.
Add test cases that explore step/key-type-and-keyhood combinations.
This commit only makes derive_input more flexible so that the key
derivation API can be tested with different key types and raw data for
each input step. The behavior of the test cases remains the same.
Exercise the library functions with calloc returning NULL for a size
of 0. Make this a separate job with UBSan (and ASan) to detect
places where we try to dereference the result of calloc(0) or to do
things like
buf = calloc(size, 1);
if (buf == NULL && size != 0) return INSUFFICIENT_MEMORY;
memcpy(buf, source, size);
which has undefined behavior when buf is NULL at the memcpy call even
if size is 0.
This is needed because other test components jobs either use the system
malloc which returns non-NULL on Linux and FreeBSD, or the
memory_buffer_alloc malloc which returns NULL but does not give as
useful feedback with ASan (because the whole heap is a single C
object).
Add a very basic test of calloc to the selftest program. The selftest
program acts in its capacity as a platform compatibility checker rather
than in its capacity as a test of the library.
The main objective is to report whether calloc returns NULL for a size
of 0. Also observe whether a free/alloc sequence returns the address
that was just freed and whether a size overflow is properly detected.
The current test generator code accepts multiple colons as a
separator, but this is just happenstance due to how the code, it isn't
robust. Replace "::" by ":", which is more future-proof and allows
simple separator-based navigation.
Make check-test-cases.py pass.
Prior to this commit, there were many repeated test descriptions, but
none with the same test data and dependencies and comments, as checked
with the following command:
for x in tests/suites/*.data; do perl -00 -ne 'warn "$ARGV: $. = $seen{$_}\n" if $seen{$_}; $seen{$_}=$.' $x; done
Wherever a test suite contains multiple test cases with the exact same
description, add " [#1]", " [#2]", etc. to make the descriptions
unique. We don't currently use this particular arrangement of
punctuation, so all occurrences of " [#" were added by this script.
I used the following ad hoc code:
import sys
def fix_test_suite(data_file_name):
in_paragraph = False
total = {}
index = {}
lines = None
with open(data_file_name) as data_file:
lines = list(data_file.readlines())
for line in lines:
if line == '\n':
in_paragraph = False
continue
if line.startswith('#'):
continue
if not in_paragraph:
# This is a test case description line.
total[line] = total.get(line, 0) + 1
index[line] = 0
in_paragraph = True
with open(data_file_name, 'w') as data_file:
for line in lines:
if line in total and total[line] > 1:
index[line] += 1
line = '%s [#%d]\n' % (line[:-1], index[line])
data_file.write(line)
for data_file_name in sys.argv[1:]:
fix_test_suite(data_file_name)
A test case for 32+0 was present three times, evidently overeager
copy-paste. Replace the duplicates by test cases that read more than
32 bytes, which exercises HKDF a little more (32 bytes is significant
because HKDF-SHA-256 produces output in blocks of 32 bytes).
I obtained the test data by running our implementation, because we're
confident in our implementation now thanks to other test cases: this
data is useful as a non-regression test.
There should have been a good-saltlen test case and a bad-saltlen test
case for both sizes 522 and 528, but the 522-bad-saltlen test case was
missing and the 528-good-saltlen test case was repeated. Fix this.
Don't use semicolons in test case descriptions. The test outcome file
is a semicolon-separated CSV file without quotes to keep things
simple, so fields in that file may not contain semicolons.
The signature must have exactly the same length as the key, it can't
be longer. Fix#258
If the signature doesn't have the correct size, that's an invalid
signature, not a problem with an output buffer size. Fix the error code.
Add test cases.
In psa_asymmetric_sign, immediately reject an empty signature buffer.
This can never be right.
Add test cases (one RSA and one ECDSA).
Change the SE HAL mock tests not to use an empty signature buffer.
Zero-length keys are rejected at creation time, so we don't need any
special handling internally.
When exporting a key, we do need to take care of the case where the
output buffer is empty, but this is easy: an empty output buffer is
never valid.
Add tests for derivation.
Test both 7 bits and 9 bits, in case the implementation truncated the
bit size down and 7 was rejected as 0 rather than because it isn't a
multiple of 8.
There is no corresponding test for import because import determines
the key size from the key data, which is always a whole number of bytes.
Keys of size 0 generally don't make sense: a key is supposed to be
secret. There is one edge case which is "raw data" keys, which are
useful to store non-key objects in the same storage location as keys.
However those are also problematic because they involve a zero-length
buffer. Manipulating zero-length buffers in C requires special cases
with functions like malloc() and memcpy(). Additionally, 0 as a key
size already has a meaning "unspecified", which does not always
overlap seamlessly with the meaning "0".
Therefore, forbid keys of size 0. No implementation may accept them.
Clarify how key creation functions use attributes. Explain the meaning
of attribute values, espcially what 0 means in each field where it has
a special meaning. Explain what an algorithm usage policy can be (an
algorithm, a wildcard with ANY_HASH, or 0).