Showing with 206 additions and 34 deletions.
  1. +2 −1 man/tpm2_nvdefine.1.md
  2. +6 −5 man/tpm2_nvwrite.1.md
  3. +73 −5 test/system/test_tpm2_nv.sh
  4. +7 −2 tools/tpm2_nvdefine.c
  5. +118 −21 tools/tpm2_nvwrite.c
3 changes: 2 additions & 1 deletion man/tpm2_nvdefine.1.md
Expand Up @@ -25,7 +25,8 @@
* **0x4000000C** for **TPM_RH_PLATFORM**

* **-s**, **--size**=_SIZE_:
specifies the size of data area in bytes.
specifies the size of data area in bytes. Defaults to MAX_NV_INDEX_SIZE
which is typically 2048.

* **-t**, **--attributes**=_ATTRIBUTES_
Specifies the attribute values for the nv region used when creating the
Expand Down
11 changes: 6 additions & 5 deletions man/tpm2_nvwrite.1.md
Expand Up @@ -8,11 +8,12 @@

# SYNOPSIS

**tpm2_nvwrite** [*OPTIONS*]
**tpm2_nvwrite** [*OPTIONS*] _FILE_

# DESCRIPTION

**tpm2_nvwrite**(1) - Write data to a Non-Volatile (NV) index.
**tpm2_nvwrite**(1) - Write data specified via _FILE_ to a Non-Volatile (NV) index.
If _FILE_ is not specified, it defaults to stdin.

# OPTIONS

Expand All @@ -28,12 +29,12 @@
specifies the password of authHandle. Passwords should follow the
"password formatting standards, see section "Password Formatting".

* **-f**, **--file**=_FILE_:
The data to write.

* **-S**, **--input-session-handle**=_SIZE_:
Optional Input session handle from a policy session for authorization.

* **-o**, **--offset**=_OFFSET_:
The offset within the NV index to start writing at.

[common options](common/options.md)

[common tcti options](common/tcti.md)
Expand Down
78 changes: 73 additions & 5 deletions test/system/test_tpm2_nv.sh
Expand Up @@ -40,9 +40,10 @@ large_file_read_name="nv.test_large_w"
cleanup() {
tpm2_nvrelease -Q -x $nv_test_index -a $nv_auth_handle 2>/dev/null || true
tpm2_nvrelease -Q -x 0x1500016 -a 0x40000001 2>/dev/null || true
tpm2_nvrelease -Q -x 0x1500015 -a 0x40000001 -P owner 2>/dev/null || true

rm -f policy.bin test.bin nv.test_w $large_file_name $large_file_read_name \
nv.readlock
nv.readlock foo.dat cmp.dat
}

trap cleanup EXIT
Expand All @@ -55,18 +56,51 @@ trap onerror ERR

cleanup

tpm2_takeownership -c
tpm2_takeownership -c

tpm2_nvdefine -Q -x $nv_test_index -a $nv_auth_handle -s 32 -t "ownerread|policywrite|ownerwrite"

echo "please123abc" > nv.test_w

tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle -f nv.test_w
tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle nv.test_w

tpm2_nvread -Q -x $nv_test_index -a $nv_auth_handle -s 32 -o 0

tpm2_nvlist | grep -q -i $nv_test_index

# Test writing to and reading from an offset by:
# 1. writing "foo" into the nv file at an offset
# 2. writing to the same offset in the nv index
# 3. reading back the index
# 4. comparing the result.

echo -n "foo" > foo.dat

dd if=foo.dat of=nv.test_w bs=1 seek=4 conv=notrunc 2>/dev/null

# Test a pipe input
cat foo.dat | tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle -o 4

tpm2_nvread -x $nv_test_index -a $nv_auth_handle -s 13 | xxd -r > cmp.dat

cmp nv.test_w cmp.dat

# Writing at an offset and data size too big shouldn't result in a change
# to the index value.

trap - ERR

tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle -o 30 foo.dat 2>/dev/null
if [ $? -eq 0 ]; then
echo "Writing past the public size shouldn't work!"
exit 1
fi
trap onerror ERR

tpm2_nvread -x $nv_test_index -a $nv_auth_handle -s 13 | xxd -r > cmp.dat

cmp nv.test_w cmp.dat

tpm2_nvrelease -x $nv_test_index -a $nv_auth_handle

echo "f28230c080bbe417141199e36d18978228d8948fc10a6a24921b9eba6bb1d988" \
Expand All @@ -92,7 +126,8 @@ tpm2_nvdefine -Q -x $nv_test_index -a $nv_auth_handle -s $large_file_size -t 0x2

base64 /dev/urandom | head -c $(($large_file_size)) > $large_file_name

tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle -f $large_file_name
# Test file input redirection
tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle <<< $large_file_name

tpm2_nvread -Q -x $nv_test_index -a $nv_auth_handle | xxd -r > $large_file_read_name

Expand All @@ -109,7 +144,7 @@ tpm2_nvdefine -Q -x $nv_test_index -a $nv_auth_handle -s 32 -t "ownerread|policy

echo "foobar" > nv.readlock

tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle -f nv.readlock
tpm2_nvwrite -Q -x $nv_test_index -a $nv_auth_handle nv.readlock

tpm2_nvread -Q -x $nv_test_index -a $nv_auth_handle -s 6 -o 0

Expand All @@ -124,4 +159,37 @@ if [ $? != 1 ];then
exit 1
fi

#
# Test that owner and index passwords work by
# 1. Setting up the owner password
# 2. Defining an nv index that can be satisfied by an:
# a. Owner authorization
# b. Index authorization
# 3. Using index and owner based auth during write/read operations
# 4. Testing that auth is needed or a failure occurs.
#
trap onerror ERR

tpm2_takeownership -o owner

tpm2_nvdefine -x 0x1500015 -a 0x40000001 -s 32 \
-t "policyread|policywrite|authread|authwrite|ownerwrite|ownerread" \
-I "index" -P "owner"

# Use index password write/read
tpm2_nvwrite -Q -x 0x1500015 -a 0x1500015 -P "index" nv.test_w
tpm2_nvread -Q -x 0x1500015 -a 0x1500015 -P "index"

# use owner password
tpm2_nvwrite -Q -x 0x1500015 -a 0x40000001 -P "owner" nv.test_w
tpm2_nvread -Q -x 0x1500015 -a 0x40000001 -P "owner"

# Check a bad password fails
trap - ERR
tpm2_nvwrite -Q -x 0x1500015 -a 0x1500015 -P "wrong" nv.test_w 2>/dev/null
if [ $? -eq 0 ];then
echo "nvwrite with bad password should fail!"
exit 1
fi

exit 0
9 changes: 7 additions & 2 deletions tools/tpm2_nvdefine.c
Expand Up @@ -49,7 +49,7 @@ typedef struct tpm_nvdefine_ctx tpm_nvdefine_ctx;
struct tpm_nvdefine_ctx {
UINT32 nvIndex;
UINT32 authHandle;
UINT32 size;
UINT16 size;
TPMA_NV nvAttribute;
TPM2B_AUTH nvAuth;
TPMS_AUTH_COMMAND session_data;
Expand All @@ -61,6 +61,7 @@ static tpm_nvdefine_ctx ctx = {
.nvAttribute = SESSION_ATTRIBUTES_INIT(0),
.session_data = TPMS_AUTH_COMMAND_INIT(TPM_RS_PW),
.nvAuth = TPM2B_EMPTY_INIT,
.size = MAX_NV_INDEX_SIZE,
};

static int nv_space_define(TSS2_SYS_CONTEXT *sapi_context) {
Expand Down Expand Up @@ -93,6 +94,10 @@ static int nv_space_define(TSS2_SYS_CONTEXT *sapi_context) {
// Now set the attributes.
public_info.t.nvPublic.attributes.val = ctx.nvAttribute.val;

if (!ctx.size) {
LOG_WARN("Defining an index with size 0");
}

if (ctx.policy_file) {
public_info.t.nvPublic.authPolicy.t.size = BUFFER_SIZE(TPM2B_DIGEST, buffer);
if(!files_load_bytes_from_path(ctx.policy_file, public_info.t.nvPublic.authPolicy.t.buffer, &public_info.t.nvPublic.authPolicy.t.size )) {
Expand Down Expand Up @@ -154,7 +159,7 @@ static bool on_option(char key, char *value) {
}
break;
case 's':
result = tpm2_util_string_to_uint32(value, &ctx.size);
result = tpm2_util_string_to_uint16(value, &ctx.size);
if (!result) {
LOG_ERR("Could not convert size to number, got: \"%s\"",
value);
Expand Down