mirror of
https://github.com/tpm2dev/tpm.dev.tutorials.git
synced 2024-11-23 22:32:10 +00:00
Merge pull request #16 from nicowilliams/master
Add sample encrypt-to-TPM scripts and parameter encryption introduction
This commit is contained in:
commit
d0cbddfea4
6 changed files with 689 additions and 7 deletions
|
@ -1,6 +1,7 @@
|
||||||
# What Attestation is
|
# What Attestation is
|
||||||
|
|
||||||
A computer can use a TPM to demonstrate:
|
An [enrolled device](/Enrollment/README.md) can use a TPM to
|
||||||
|
demonstrate:
|
||||||
|
|
||||||
- possession of a valid TPM
|
- possession of a valid TPM
|
||||||
|
|
||||||
|
@ -820,6 +821,11 @@ We'll discuss two ways to do this:
|
||||||
the value zero so that extending it can disable use of
|
the value zero so that extending it can disable use of
|
||||||
`TPM2_MakeCredential()` post-boot.
|
`TPM2_MakeCredential()` post-boot.
|
||||||
|
|
||||||
|
We have two sample bash scripts demonstrating this approach:
|
||||||
|
|
||||||
|
- [`send-to-tpm.sh`](/Enrollment/send-to-tpm.sh)
|
||||||
|
- [`tpm-receive.sh`](/Enrollment/tpm-receive.sh)
|
||||||
|
|
||||||
- use an `LTAK` -- a long-term `AK`
|
- use an `LTAK` -- a long-term `AK`
|
||||||
|
|
||||||
I.e., an `AK` that lacks the `stClear` attribute, and _preferably_
|
I.e., an `AK` that lacks the `stClear` attribute, and _preferably_
|
||||||
|
|
|
@ -38,7 +38,7 @@ device using only that information.
|
||||||
- encrypted filesystems?
|
- encrypted filesystems?
|
||||||
- device credentials? (e.g., TLS server certificates, Kerberos keys ["keytabs"], etc.)
|
- device credentials? (e.g., TLS server certificates, Kerberos keys ["keytabs"], etc.)
|
||||||
|
|
||||||
# Secrets Transport
|
# Secrets Long-Term Storage and Transport
|
||||||
|
|
||||||
Every time an enrolled device reboots, or possibly more often, it may
|
Every time an enrolled device reboots, or possibly more often, it may
|
||||||
have to connect to an attestation server to obtain secrets from it that
|
have to connect to an attestation server to obtain secrets from it that
|
||||||
|
@ -46,8 +46,95 @@ the device needs in order to proceed. For example, filesystem
|
||||||
decryption keys, general network access, device authentication
|
decryption keys, general network access, device authentication
|
||||||
credentials, etc.
|
credentials, etc.
|
||||||
|
|
||||||
See [attestation](/Attestation/README.md) for details of how to
|
See [attestation](/Attestation/README.md#Secret-Transport-Sub-Protocols)
|
||||||
transport secrets onto an enrolled device post-enrollment.
|
for details of how to store and transport secrets onto an enrolled
|
||||||
|
device post-enrollment.
|
||||||
|
|
||||||
|
## Encrypt-to-TPM Sample Scripts
|
||||||
|
|
||||||
|
A pair of scripts are included here to demonstrate how to make long-term
|
||||||
|
secrets encrypted to TPMs for use in
|
||||||
|
[attestation](/Attestation/README.md) protocols. The method used is the
|
||||||
|
one described in the [attestation
|
||||||
|
tutorial](/Attestation/README.md#Secret-Transport-Sub-Protocols) using
|
||||||
|
[`TPM2_MakeCredential()`](/TPM-Commands/TPM2_MakeCredential.md) and
|
||||||
|
[`TPM2_ActivateCredential()`](/TPM-Commands/TPM2_ActivateCredential.md)
|
||||||
|
with a hard-coded, _well-known_ activation key (`WK`) to implement
|
||||||
|
encryption-to-`EKpub` with (optional) sender-asserted authorization
|
||||||
|
policy:
|
||||||
|
|
||||||
|
- [`send-to-tpm.sh`](send-to-tpm.sh)
|
||||||
|
- [`tpm-receive.sh`](tpm-receive.sh)
|
||||||
|
|
||||||
|
You can use these scripts like so:
|
||||||
|
|
||||||
|
- without policy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
: ; # Make a secret
|
||||||
|
: ; dd if=/dev/urandom of=secret.bin bs=16 count=1
|
||||||
|
: ;
|
||||||
|
: ; # Encrypt the secret to some TPM whose EKpub is in a file named
|
||||||
|
: ; # ek.pub:
|
||||||
|
: ; /safeboot/sbin/send-to-tpm.sh ek.pub secret.bin cipher.bin
|
||||||
|
fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e
|
||||||
|
7fdad037a921f7eec4f97c08722692028e96888f0b970dc7b3bb6a9c97e8f988
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
: ; # Decrypt the secret:
|
||||||
|
: ; tpm-receive.sh cipher.bin secret.bin
|
||||||
|
fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e
|
||||||
|
7fdad037a921f7eec4f97c08722692028e96888f0b970dc7b3bb6a9c97e8f988
|
||||||
|
name: 000be1fe1b777ead331f2da896ced2bf7a3949d732a0c6adf6f0a292567d587c4408
|
||||||
|
837197674484b3f81a90cc8d46a5d724fd52d76e06520b64f2a1da1b331469aa
|
||||||
|
fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e
|
||||||
|
7fdad037a921f7eec4f97c08722692028e96888f0b970dc7b3bb6a9c97e8f988
|
||||||
|
certinfodata:b7bd59980628c33a14377d53e165c229
|
||||||
|
: ;
|
||||||
|
- with policy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
: ; # Make up a policy (here that PCR11 must be unextended):
|
||||||
|
: ; dd if=/dev/zero of=pcr.dat bs=32 count=1
|
||||||
|
: ; policy=(tpm2 policypcr -l sha256:11 -f pcr.dat)
|
||||||
|
: ;
|
||||||
|
: ; send-to-tpm.sh ek.pub secret.bin cipher.bin "${policy[@]}"
|
||||||
|
fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e
|
||||||
|
7fdad037a921f7eec4f97c08722692028e96888f0b970dc7b3bb6a9c97e8f988
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
: ; # We have to satisfy the same policy on the receive side:
|
||||||
|
: ; policy=(tpm2 policypcr -l sha256:11 -f pcr.dat)
|
||||||
|
: ;
|
||||||
|
: ; tpm-receive.sh -f cipher.bin "${policy[@]}"
|
||||||
|
fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e
|
||||||
|
7fdad037a921f7eec4f97c08722692028e96888f0b970dc7b3bb6a9c97e8f988
|
||||||
|
name: 000be1fe1b777ead331f2da896ced2bf7a3949d732a0c6adf6f0a292567d587c4408
|
||||||
|
837197674484b3f81a90cc8d46a5d724fd52d76e06520b64f2a1da1b331469aa
|
||||||
|
fd32fa22c52cfc8e1a0c29eb38519f87084cab0b04b0d8f020a4d38b2f4e223e
|
||||||
|
7fdad037a921f7eec4f97c08722692028e96888f0b970dc7b3bb6a9c97e8f988
|
||||||
|
certinfodata:b7bd59980628c33a14377d53e165c229
|
||||||
|
: ;
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple policy commands can be separated with a quoted semi-colon:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
send-to-tpm.sh ... tpm2 policyblah ... \; policyfoo ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple policy commands can be separated with a quoted semi-colon:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
send-to-tpm.sh ... tpm2 policyblah ... \; policyfoo ...
|
||||||
|
```
|
||||||
|
|
||||||
|
When a policy is specified, these scripts will automatically set the
|
||||||
|
`adminWithPolicy` attribute of the activation object, and will add
|
||||||
|
`tpm2 policycommandcode TPM2_CC_ActivateCredential` to the policy, as
|
||||||
|
that is required for activation objects with `adminWithPolicy` set.
|
||||||
|
|
||||||
# Enrollment Semantics
|
# Enrollment Semantics
|
||||||
|
|
||||||
|
|
165
Enrollment/send-to-tpm.sh
Executable file
165
Enrollment/send-to-tpm.sh
Executable file
|
@ -0,0 +1,165 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROG=${0##*/}
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
((${1:-1} > 0)) && exec 1>&2
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $PROG EK-PUB-FILE SECRET-FILE OUT-FILE
|
||||||
|
$PROG EK-PUB-FILE SECRET-FILE OUT-FILE [POLICY-CMD [ARGS [\\; ...]]]
|
||||||
|
$PROG -P well-known-key-name EK-PUB-FILE SECRET-FILE OUT-FILE
|
||||||
|
|
||||||
|
Encrypts a small secret to a TPM's EKpub with the caller's choice of
|
||||||
|
policy.
|
||||||
|
|
||||||
|
Policies should be specified as a sequence of {tpm2 policy...}
|
||||||
|
commands, with all necessary arguments except for {--session}|{-S}
|
||||||
|
and {--policy}|{-L} options. Also, no need to include {tpm2
|
||||||
|
policycommandcode}, as that will get added. E.g.:
|
||||||
|
|
||||||
|
$ $PROG ./ekpub ./secret ./madecredential \\
|
||||||
|
tpm2 policypcr -l "sha256:0,1,2,3" -f pcrs
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-h This help message.
|
||||||
|
-P WKname Use the given cryptographic name binding a policy for
|
||||||
|
recipient to meet.
|
||||||
|
-f Overwrite OUT-FILE.
|
||||||
|
-x Trace this script.
|
||||||
|
EOF
|
||||||
|
exit ${1:-1}
|
||||||
|
}
|
||||||
|
|
||||||
|
force=false
|
||||||
|
wkname=
|
||||||
|
while getopts +:hfxP: opt; do
|
||||||
|
case "$opt" in
|
||||||
|
P) wkname=$OPTARG;;
|
||||||
|
h) usage 0;;
|
||||||
|
f) force=true;;
|
||||||
|
x) set -vx;;
|
||||||
|
*) usage;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
(($# >= 3)) || usage
|
||||||
|
ekpub_file=$1
|
||||||
|
secret_file=$2
|
||||||
|
out_file=$3
|
||||||
|
shift 3
|
||||||
|
|
||||||
|
function err {
|
||||||
|
echo "ERROR: $*" 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -f ${ekpub_file:-} ]] || usage
|
||||||
|
[[ -f ${secret_file:-} ]] || usage
|
||||||
|
[[ -f ${out_file:-} ]] && $force && rm -f "${out_file:-}"
|
||||||
|
[[ -f ${out_file:-} ]] && err "output file ($out_file) exists"
|
||||||
|
|
||||||
|
# Make a temp dir and remove it when we exit:
|
||||||
|
d=
|
||||||
|
trap 'rm -rf "$d"' EXIT
|
||||||
|
d=$(mktemp -d)
|
||||||
|
|
||||||
|
function exec_policy {
|
||||||
|
local add_commandcode=true
|
||||||
|
local has_policy=false
|
||||||
|
|
||||||
|
while (($# > 0)); do
|
||||||
|
has_policy=true
|
||||||
|
cmd=()
|
||||||
|
while (($# > 0)) && [[ $1 != ';' ]]; do
|
||||||
|
cmd+=("$1")
|
||||||
|
if ((${#cmd[@]} == 1)) && [[ ${cmd[0]} = tpm2_* ]]; then
|
||||||
|
cmd+=(--session "${d}/session.ctx" --policy "${d}/policy")
|
||||||
|
elif ((${#cmd[@]} == 2)) && [[ ${cmd[0]} = tpm2 ]]; then
|
||||||
|
cmd+=(--session "${d}/session.ctx" --policy "${d}/policy")
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
(($# > 0)) && shift
|
||||||
|
# Run the policy command in the temp dir. It -or the last command- must
|
||||||
|
# leave a file there named 'policy'.
|
||||||
|
"${cmd[@]}"
|
||||||
|
if [[ ${cmd[0]} = tpm2 ]] && ((${#cmd[@]} == 1)); then
|
||||||
|
echo "Policy is incomplete" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
[[ ${cmd[0]} = tpm2 && ${cmd[1]} = policycommandcode ]] &&
|
||||||
|
add_commandcode=false
|
||||||
|
[[ ${cmd[0]} = tpm2_policycommandcode ]] && add_commandcode=false
|
||||||
|
done
|
||||||
|
$has_policy && $add_commandcode &&
|
||||||
|
tpm2 policycommandcode --session "${d}/session.ctx" \
|
||||||
|
--policy "${d}/policy" \
|
||||||
|
TPM2_CC_ActivateCredential
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_policyDigest {
|
||||||
|
# Start a trial session, execute the given policy commands, save the
|
||||||
|
# policyDigest.
|
||||||
|
tpm2 startauthsession --session "${d}/session.ctx"
|
||||||
|
exec_policy "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function wkname {
|
||||||
|
local attrs='decrypt|sign'
|
||||||
|
local has_policy
|
||||||
|
|
||||||
|
# This is the WK. It was generated with:
|
||||||
|
# openssl genpkey -genparam \
|
||||||
|
# -algorithm EC \
|
||||||
|
# -out "${d}/ecp.pem" \
|
||||||
|
# -pkeyopt ec_paramgen_curve:secp384r1 \
|
||||||
|
# -pkeyopt ec_param_enc:named_curve
|
||||||
|
# openssl genpkey -paramfile "${d}/ecp.pem"
|
||||||
|
cat > "${d}/wkpriv.pem" <<EOF
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAlMnCWue7CfXjNLibH
|
||||||
|
PTJrsOLUcoxqU3FLWYEWMI+HuPnzcwwl7SkKN6cpf4H3oQihZANiAAQ1pw6D5QVw
|
||||||
|
vymljYVDyrUriOet8zPB/9tq9XJ7A54qsVkaVufAuEJ6GIvD4xUZ27manMosJADS
|
||||||
|
aW2TLJkwxecRh2eTwPtSx2U32M2/yHeuWRV/0juiIozefPsTAlHAi3E=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
EOF
|
||||||
|
|
||||||
|
tpm2 flushcontext --transient-object
|
||||||
|
tpm2 flushcontext --loaded-session
|
||||||
|
tpm2 flushcontext --saved-session 1>&2
|
||||||
|
|
||||||
|
# Load
|
||||||
|
attrs='decrypt|sign'
|
||||||
|
if (($# > 0)); then
|
||||||
|
make_policyDigest "$@" 1>&2
|
||||||
|
attrs='adminwithpolicy|decrypt|sign'
|
||||||
|
has_policy=true
|
||||||
|
|
||||||
|
# Flush again, but this time not saved sessions
|
||||||
|
tpm2 flushcontext --transient-object 1>&2
|
||||||
|
tpm2 flushcontext --loaded-session 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load the WK
|
||||||
|
tpm2 loadexternal -C n \
|
||||||
|
-Gecc \
|
||||||
|
-r "${d}/wkpriv.pem" \
|
||||||
|
${has_policy:+-L "${d}/policy"} \
|
||||||
|
-a "$attrs" \
|
||||||
|
-c "${d}/wk.ctx" |
|
||||||
|
grep ^name: | cut -d' ' -f2
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -z $wkname ]] && wkname=$(wkname "$@")
|
||||||
|
|
||||||
|
tpm2 makecredential \
|
||||||
|
--tcti "none" \
|
||||||
|
--encryption-key "${ekpub_file}" \
|
||||||
|
--name "$wkname" \
|
||||||
|
--secret "${secret_file}" \
|
||||||
|
--credential-blob "$out_file"
|
194
Enrollment/tpm-receive.sh
Executable file
194
Enrollment/tpm-receive.sh
Executable file
|
@ -0,0 +1,194 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROG=${0##*/}
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
function usage {
|
||||||
|
echo "Usage: $PROG [OPTIONS] CIPHERTEXT-FILE OUT-FILE [POLICY-CMD [ARGS] [\; ...]]"
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $PROG CIPHERTEXT-FILE OUT-FILE [POLICY-CMD [ARGS] [;] ...]
|
||||||
|
|
||||||
|
"Activates" (decrypts) CIPHERTEXT-FILE made with TPM2_MakeCredential and
|
||||||
|
writes the plaintext to OUT-FILE. If the sender asserted some policy,
|
||||||
|
that policy must be repeated when invoking this program to decrypt the
|
||||||
|
secret.
|
||||||
|
|
||||||
|
Policies should be specified as a sequence of {tpm2 policy...}
|
||||||
|
commands, with all necessary arguments except for {--session}|{-S}
|
||||||
|
and {--policy}|{-L} options. Also, no need to include {tpm2
|
||||||
|
policycommandcode}, as that will get added. E.g.:
|
||||||
|
|
||||||
|
$ $PROG ./ekpub ./secret ./madecredential \\
|
||||||
|
tpm2 policypcr -l "sha256:0,1,2,3" -f pcrs
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-h This help message.
|
||||||
|
-f Overwrite OUT-FILE.
|
||||||
|
-x Trace this script.
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
force=false
|
||||||
|
verbose=false
|
||||||
|
while getopts +:hfvx opt; do
|
||||||
|
case "$opt" in
|
||||||
|
h) usage 0;;
|
||||||
|
f) force=true;;
|
||||||
|
v) verbose=true;;
|
||||||
|
x) set -vx;;
|
||||||
|
*) usage;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
(($# >= 2)) || usage
|
||||||
|
ciphertext_file=$1
|
||||||
|
out_file=$2
|
||||||
|
shift 2
|
||||||
|
|
||||||
|
[[ -f ${ciphertext_file:-} ]] || usage
|
||||||
|
[[ -f ${out_file:-} ]] && $force && rm -f "$out_file"
|
||||||
|
[[ -f ${out_file:-} ]] && usage
|
||||||
|
|
||||||
|
d=
|
||||||
|
trap 'rm -rf "$d"' EXIT
|
||||||
|
d=$(mktemp -d)
|
||||||
|
|
||||||
|
function v {
|
||||||
|
if $verbose; then
|
||||||
|
printf 'Running:'
|
||||||
|
printf ' %q' "$@"
|
||||||
|
printf '\n'
|
||||||
|
fi >/dev/tty || true
|
||||||
|
if "$@"; then
|
||||||
|
$verbose && printf '(SUCCESS)\n' >/dev/tty || true
|
||||||
|
else
|
||||||
|
stat=$?
|
||||||
|
printf 'ERROR: Command exited with %d\n' $stat >/dev/tty || true
|
||||||
|
return $stat
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec_policy {
|
||||||
|
local add_commandcode=true
|
||||||
|
local has_policy=false
|
||||||
|
|
||||||
|
while (($# > 0)); do
|
||||||
|
has_policy=true
|
||||||
|
cmd=()
|
||||||
|
while (($# > 0)) && [[ $1 != ';' ]]; do
|
||||||
|
cmd+=("$1")
|
||||||
|
if ((${#cmd[@]} == 1)) && [[ ${cmd[0]} = tpm2_* ]]; then
|
||||||
|
cmd+=(--session "${d}/session.ctx" --policy "${d}/policy")
|
||||||
|
elif ((${#cmd[@]} == 2)) && [[ ${cmd[0]} = tpm2 ]]; then
|
||||||
|
cmd+=(--session "${d}/session.ctx" --policy "${d}/policy")
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
(($# > 0)) && shift
|
||||||
|
# Run the policy command in the temp dir. It -or the last command- must
|
||||||
|
# leave a file there named 'policy'.
|
||||||
|
"${cmd[@]}"
|
||||||
|
if [[ ${cmd[0]} = tpm2 ]] && ((${#cmd[@]} == 1)); then
|
||||||
|
echo "Policy is incomplete" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
[[ ${cmd[0]} = tpm2 && ${cmd[1]} = policycommandcode ]] &&
|
||||||
|
add_commandcode=false
|
||||||
|
[[ ${cmd[0]} = tpm2_policycommandcode ]] && add_commandcode=false
|
||||||
|
done
|
||||||
|
$has_policy && $add_commandcode &&
|
||||||
|
tpm2 policycommandcode --session "${d}/session.ctx" \
|
||||||
|
--policy "${d}/policy" \
|
||||||
|
TPM2_CC_ActivateCredential
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_policyDigest {
|
||||||
|
tpm2 flushcontext --transient-object
|
||||||
|
tpm2 flushcontext --loaded-session
|
||||||
|
v tpm2 startauthsession --session "${d}/session.ctx"
|
||||||
|
exec_policy "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the EK handle:
|
||||||
|
tpm2 flushcontext --transient-object
|
||||||
|
tpm2 flushcontext --loaded-session
|
||||||
|
tpm2 flushcontext --saved-session 1>&2
|
||||||
|
tpm2 createek --key-algorithm rsa \
|
||||||
|
--ek-context "${d}/ek.ctx" \
|
||||||
|
--public "${d}/ek.pub"
|
||||||
|
|
||||||
|
# Make policyDigest and load WK
|
||||||
|
attrs='decrypt|sign'
|
||||||
|
adminwithpolicy=
|
||||||
|
if (($# > 0)); then
|
||||||
|
make_policyDigest "$@"
|
||||||
|
attrs='adminwithpolicy|decrypt|sign'
|
||||||
|
adminwithpolicy=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "${d}/session.ctx"
|
||||||
|
|
||||||
|
# This is the WK. It was generated with:
|
||||||
|
# openssl genpkey -genparam \
|
||||||
|
# -algorithm EC \
|
||||||
|
# -out "${d}/ecp.pem" \
|
||||||
|
# -pkeyopt ec_paramgen_curve:secp384r1 \
|
||||||
|
# -pkeyopt ec_param_enc:named_curve
|
||||||
|
# openssl genpkey -paramfile "${d}/ecp.pem"
|
||||||
|
cat > "${d}/wkpriv.pem" <<EOF
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAlMnCWue7CfXjNLibH
|
||||||
|
PTJrsOLUcoxqU3FLWYEWMI+HuPnzcwwl7SkKN6cpf4H3oQihZANiAAQ1pw6D5QVw
|
||||||
|
vymljYVDyrUriOet8zPB/9tq9XJ7A54qsVkaVufAuEJ6GIvD4xUZ27manMosJADS
|
||||||
|
aW2TLJkwxecRh2eTwPtSx2U32M2/yHeuWRV/0juiIozefPsTAlHAi3E=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Load the WK
|
||||||
|
v tpm2 flushcontext --transient-object 1>&2
|
||||||
|
v tpm2 flushcontext --loaded-session 1>&2
|
||||||
|
if v tpm2 loadexternal -C n \
|
||||||
|
-Gecc \
|
||||||
|
-r "${d}/wkpriv.pem" \
|
||||||
|
${adminwithpolicy:+-L "${d}/policy"} \
|
||||||
|
-a "$attrs" \
|
||||||
|
-c "${d}/wk.ctx" > "${d}/out" 2> "${d}/err"; then
|
||||||
|
cat "${d}/out" 1>&2
|
||||||
|
else
|
||||||
|
stat=$?
|
||||||
|
echo "ERROR: Failed to load WK:" 1>&2
|
||||||
|
cat "${d}/out"
|
||||||
|
cat "${d}/err" 1>&2
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create empty auth session for EK
|
||||||
|
v tpm2 flushcontext --transient-object
|
||||||
|
v tpm2 flushcontext --loaded-session
|
||||||
|
v tpm2 startauthsession --session "${d}/sessionek.ctx" --policy-session
|
||||||
|
v tpm2 policysecret --session "${d}/sessionek.ctx" --object-context endorsement
|
||||||
|
|
||||||
|
activatecredential_args=()
|
||||||
|
if (($# > 0)); then
|
||||||
|
activatecredential_args+=(--credentialedkey-auth session:"${d}/session.ctx")
|
||||||
|
# Create auth session for the WK, since it has adminWithPolicy
|
||||||
|
v tpm2 flushcontext --transient-object
|
||||||
|
v tpm2 flushcontext --loaded-session
|
||||||
|
v tpm2 startauthsession --session "${d}/session.ctx" --policy-session
|
||||||
|
exec_policy "$@"
|
||||||
|
v tpm2 flushcontext --transient-object
|
||||||
|
v tpm2 flushcontext --loaded-session
|
||||||
|
fi
|
||||||
|
# Finally, ActivateCredential
|
||||||
|
$verbose && tpm2 readpublic -c "${d}/wk.ctx" | grep name:
|
||||||
|
v tpm2 activatecredential --credentialedkey-context "${d}/wk.ctx" \
|
||||||
|
"${activatecredential_args[@]}" \
|
||||||
|
--credentialkey-context "${d}/ek.ctx" \
|
||||||
|
--credentialkey-auth session:"${d}/sessionek.ctx" \
|
||||||
|
--credential-blob "$ciphertext_file" \
|
||||||
|
-o "$out_file"
|
|
@ -606,6 +606,9 @@ other state. TPM commands may check that an authorization session's
|
||||||
state satisfies the requirements for use of the argument objects passed
|
state satisfies the requirements for use of the argument objects passed
|
||||||
to the commands.
|
to the commands.
|
||||||
|
|
||||||
|
> NOTE: Every command input parameter that is a handle that requires
|
||||||
|
> authorization must have its own session associated with it.
|
||||||
|
|
||||||
### Authorization Session State
|
### Authorization Session State
|
||||||
|
|
||||||
Authorization sessions have a number of state attributes. Some of these
|
Authorization sessions have a number of state attributes. Some of these
|
||||||
|
@ -688,13 +691,89 @@ ways. These state attributes are:
|
||||||
|
|
||||||
### Encryption Sessions
|
### Encryption Sessions
|
||||||
|
|
||||||
> Work in progress.
|
|
||||||
|
|
||||||
Sessions can also be used for encrypting TPM command arguments and
|
Sessions can also be used for encrypting TPM command arguments and
|
||||||
results. This can be useful when one does not trust the path to the
|
results. This can be useful when one does not trust the path to the
|
||||||
TPM, such as when the TPM is remote.
|
TPM, such as when the TPM is remote.
|
||||||
|
|
||||||
> TODO: Discuss key exchange options, etc.
|
Only the first input parameter of a TPM command will be encrypted, and
|
||||||
|
only the first output parameter of a TPM command will be encrypted, and
|
||||||
|
that only if when that first parameter is of type `TPM2B`. Those first
|
||||||
|
`TPM2B` type command input and/or output parameters will be encrypted
|
||||||
|
with a symmetrict AES key derived from a secret key established via RSA
|
||||||
|
key transport or ECDH key agreement.
|
||||||
|
|
||||||
|
> Encryption sessions are useful for when the path to a TPM is not
|
||||||
|
> trused, such as when a TPM is a remote TPM, or when otherwise the path
|
||||||
|
> to the TPM is not trusted.
|
||||||
|
|
||||||
|
### Key Exchange for Encryption Sessions
|
||||||
|
|
||||||
|
> Encryption sessions are useful for when the path to a TPM is not
|
||||||
|
> trused, such as when a TPM is a remote TPM, or when otherwise the path
|
||||||
|
> to the TPM is not trusted. This section talks about key exchange for
|
||||||
|
> such situations.
|
||||||
|
|
||||||
|
The symmetric keys used for TPM command encryption are exchanged at
|
||||||
|
session creation time.
|
||||||
|
|
||||||
|
Keys can be provided by one of either RSA key transport or ECC key
|
||||||
|
agreement, and/or the secret `authValue` of a loaded entity.
|
||||||
|
|
||||||
|
Sessions are created with
|
||||||
|
[`TPM2_StartAuthSession()`](/TPM-Commands/TPM2_StartAuthSession.md),
|
||||||
|
which has serveral _optional_ input and output parameters related to
|
||||||
|
session encryption. In particular it provides ways to create a session
|
||||||
|
key for command parameter encryption:
|
||||||
|
|
||||||
|
- RSA key transport
|
||||||
|
|
||||||
|
The caller can encrypt a secret to a public key for which the TPM has
|
||||||
|
loaded the private key as identified by the `tpmKey` input parameter
|
||||||
|
of [`TPM2_StartAuthSession()`].
|
||||||
|
|
||||||
|
- ECDH key agreement
|
||||||
|
|
||||||
|
The caller can generate an ephemeral ECDH key and use it with the
|
||||||
|
public key of the ECDH key object identified by the `tpmKey` input
|
||||||
|
parameter of [`TPM2_StartAuthSession()`]. The TPM will use the
|
||||||
|
private key of the object identified by the `tpmKey` input parameter
|
||||||
|
and the ephemeral public key sent by the caller in the
|
||||||
|
`encryptedSalt` input parameter.
|
||||||
|
|
||||||
|
- use the `authHash` of the entity identified by the `bind` input
|
||||||
|
parameter
|
||||||
|
|
||||||
|
The caller computes the same session key as the TPM.
|
||||||
|
|
||||||
|
To authenticate the TPM and prevent active attacks, the caller of
|
||||||
|
`TPM2_StartAuthSession()` should use an `EK` as the `tpmKey` and its
|
||||||
|
`EKpub` to locally compute the session key. Alternatively the caller
|
||||||
|
can use a non-`EK` key object created over an earlier encrypted session
|
||||||
|
that authenticated the target TPM.
|
||||||
|
|
||||||
|
> A non-null `bind` parameter can be used to create a "bound" session
|
||||||
|
> that can be used to satisfy HMAC-based authorization for specific
|
||||||
|
> objects. We will not cover this in detail here.
|
||||||
|
|
||||||
|
### HMAC Sessions
|
||||||
|
|
||||||
|
An HMAC session proves the caller knows the `authValue` secret of some
|
||||||
|
entity. This functions a lot like a password, with the `authValue`
|
||||||
|
used to compute HMACs that prove possession, but with the `authValue`
|
||||||
|
generally being large and randomly generated, thus much stronger than a
|
||||||
|
password.
|
||||||
|
|
||||||
|
Typically the `authValue` of some entity should be sent encrypted to the
|
||||||
|
TPM when creating an entity, with [the encrypted session being keyed via
|
||||||
|
RSA key transport or ECDH](#Key-Exchange-for-Encryption-Sessions). This
|
||||||
|
way an `authValue`, though a simple, password-like binary string, can be
|
||||||
|
strong and secure due to being large, randomly chosen and sent over
|
||||||
|
an encrypted session.
|
||||||
|
|
||||||
|
### Password Sessions
|
||||||
|
|
||||||
|
> WIP [Say something about passwords and password sessions, besides
|
||||||
|
> "don't use them" and "support remains mostly for TPM 1.2 reasons".]
|
||||||
|
|
||||||
Alternatively a session can be for encryption of command inputs/outputs,
|
Alternatively a session can be for encryption of command inputs/outputs,
|
||||||
which is useful when the path to the TPM is not secure.
|
which is useful when the path to the TPM is not secure.
|
||||||
|
|
151
TPM-Commands/TPM2_StartAuthSession.md
Normal file
151
TPM-Commands/TPM2_StartAuthSession.md
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
# `TPM2_StartAuthSession()`
|
||||||
|
|
||||||
|
This command starts a session that can be used for authorization and/or
|
||||||
|
encryption.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- `TPMI_DH_OBJECT+ tpmKey`
|
||||||
|
|
||||||
|
This optional _input_ parameter specifies the handle of a loaded RSA
|
||||||
|
decryption key or of a loaded ECDH key.
|
||||||
|
|
||||||
|
- `TPMI_DH_ENTITY+ bind`
|
||||||
|
|
||||||
|
This parameter, if not null, references a loaded entity whose
|
||||||
|
`authValue` will be used in the session key computation.
|
||||||
|
|
||||||
|
- `TPM2B_NONCE nonceCaller`
|
||||||
|
|
||||||
|
This is a nonce chosen by the caller.
|
||||||
|
|
||||||
|
- `TPM2B_ENCRYPTED_SECRET encryptedSalt`
|
||||||
|
|
||||||
|
This optional _input_ parameter must be present if `tpmKey` is
|
||||||
|
present.
|
||||||
|
|
||||||
|
If `tpmKey` is an RSA decryption key then `encryptedSalt` must be an
|
||||||
|
RSA OEAP ciphertext that will be decrypted with the `tpmKey`. The
|
||||||
|
plaintext will be used to derive symmetric AES-CFB encryption keys.
|
||||||
|
|
||||||
|
If `tpmKey` is an ECDH key, then `encryptedSalt` must be a public key
|
||||||
|
that will be used to generate a shared secret key from which
|
||||||
|
symmetric AES-CFB encryption keys will be derived.
|
||||||
|
|
||||||
|
- `TPM_SE sessionType`
|
||||||
|
- `TPMT_SYM_DEF+ symmetric`
|
||||||
|
- `TPMI_ALG_HASH authHash`
|
||||||
|
|
||||||
|
A hash algorithm for the key derivation function.
|
||||||
|
|
||||||
|
## Outputs (success case)
|
||||||
|
|
||||||
|
- `TPMI_SH_AUTH_SESSION sessionHandle`
|
||||||
|
- `TPM2B_NONCE nonceTPM`
|
||||||
|
|
||||||
|
This is an _output_ parameter that is generated by the TPM, and it is
|
||||||
|
a nonce that is used for key derivation.
|
||||||
|
|
||||||
|
## Session Types
|
||||||
|
|
||||||
|
The `sessionType` input parameter must be one of:
|
||||||
|
|
||||||
|
- `TPM_SE_HMAC`
|
||||||
|
- `TPM_SE_POLICY`
|
||||||
|
- `TPM_SE_TRIAL`
|
||||||
|
|
||||||
|
### HMAC Sessions
|
||||||
|
|
||||||
|
If the session is to be an HMAC session authenticating knowledge of some
|
||||||
|
entity's `authValue`, then the `bind` argument must be provided.
|
||||||
|
|
||||||
|
### Authorization Sessions
|
||||||
|
|
||||||
|
For policy sessions, the caller should now call one or more
|
||||||
|
`TPM2_Policy*()` commands to execute the policy identified by the
|
||||||
|
`authPolicy` value of the entity to be accessed via this session.
|
||||||
|
|
||||||
|
### Trial Policies
|
||||||
|
|
||||||
|
For trial sessions, the caller should now call one or more
|
||||||
|
`TPM2_Policy*()` commands as will be used in future actual policy
|
||||||
|
sessions, then extract the `policyDigest` of the
|
||||||
|
session after the last policy command -- that will be a value
|
||||||
|
suitablefor use as an `authPolicy` value for TPM entities.
|
||||||
|
|
||||||
|
### Encryption Sessions
|
||||||
|
|
||||||
|
> All sessions can be used for encryption that were created with either
|
||||||
|
> or both of the `bind` input parameter and the pair of input parameters
|
||||||
|
> `tpmKey` and `encryptedSalt` set.
|
||||||
|
|
||||||
|
> Encryption sessions are useful for when the path to a TPM is not
|
||||||
|
> trused, such as when a TPM is a remote TPM, or when otherwise the path
|
||||||
|
> to the TPM is not trusted. This section talks about key exchange for
|
||||||
|
> such situations.
|
||||||
|
|
||||||
|
For encryption sessions the `symmetric` parameter should also be set.
|
||||||
|
|
||||||
|
Encryption sessions can have a session key derived from either or both
|
||||||
|
of the `authValue` of the `bind` entity or the key exchange represented
|
||||||
|
by the `tpmKey` and `encryptedSalt` inputs. The `nonceCaller` input and
|
||||||
|
the `nonceTPM` output will also salt the key derivation.
|
||||||
|
|
||||||
|
The symmetric keys used for TPM command encryption are set at session
|
||||||
|
creation time.
|
||||||
|
|
||||||
|
Session keys are derived from the `tpmKey` and `encryptedSalt` inputs
|
||||||
|
(if provided) and the `authValue` of a loaded entity referred to by
|
||||||
|
`bind` (if provided), along with the nonces and other things.
|
||||||
|
|
||||||
|
The `tpmKey` and `encryptedSalt` inputs can inject a secret either via
|
||||||
|
RSA key transport or elliptic curve Diffie-Hellman (ECDH).
|
||||||
|
|
||||||
|
The key will be derived as follows:
|
||||||
|
|
||||||
|
- if `tpmKey` and `encryptedSalt` are provided, then the key is
|
||||||
|
recovered (RSA case) or computed (ECDH case)
|
||||||
|
|
||||||
|
In the RSA case the `encryptedSalt` is the ciphertext resulting from
|
||||||
|
RSA PKCS#2 (OEAP) encryption to the public key of the object referred
|
||||||
|
to by `tpmKey`. The TPM will decrypt the `encryptedSalt` to recover
|
||||||
|
the secret.
|
||||||
|
|
||||||
|
In the ECDH case the `encryptedSalt` is an ephemeral public key, and
|
||||||
|
the secret will be the ECDH shared secret constructed from that key
|
||||||
|
and the private part of the `tpmKey`.
|
||||||
|
|
||||||
|
- then the internal `KDFa()` function will invoked as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
sessionKey := KDFa(authHash,
|
||||||
|
(bind.authValue || tmpKey.get(encryptedSalt)),
|
||||||
|
"ATH",
|
||||||
|
nonceTPM,
|
||||||
|
nonceCaller,
|
||||||
|
authHash.digestSize)
|
||||||
|
```
|
||||||
|
|
||||||
|
where:
|
||||||
|
|
||||||
|
- `bind.authValue` is the `authValue` of the `bind` entity (if
|
||||||
|
provided)
|
||||||
|
|
||||||
|
- `tmpKey.get(encryptedSalt)` is the result of RSA decryption of
|
||||||
|
`encryptedSalt` if `tpmKey` is an RSA key, or the result of ECDH
|
||||||
|
key agreement between the private part of `tpmKey` and the public
|
||||||
|
ECDH key in `encryptedSalt` if `tpmKey` is an ECDH key
|
||||||
|
|
||||||
|
To avoid active attacks, one would use the EK as the `tpmKey` input
|
||||||
|
parameter of `TPM2_StartAuthSession()`. Or one could use a `tpmKey`
|
||||||
|
input created with, e.g., `TPM2_Create()` over another encrypted session
|
||||||
|
that itself used the EK as its `tpmKey` input.
|
||||||
|
|
||||||
|
> A non-null `bind` parameter can be used to create a "bound" session
|
||||||
|
> that can be used to satisfy HMAC-based authorization for specific
|
||||||
|
> objects. We will not cover this in detail here.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [TCG TPM Library part 1: Architecture, sections 18.6, 19, and 21](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part1_Architecture.pdf)
|
||||||
|
- [TCG TPM Library part 3: Commands, section 11.1](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part3_Commands_pub.pdf)
|
Loading…
Reference in a new issue