summarylogtreecommitdiffstats
path: root/hook_tpm2
blob: 1488b4137986cbccbf6e290cc0dc50bfcd86ab0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/ash

run_hook() {
    local ckeyfile tpmkeypub tpmkeypriv tpmkeyparent tpmkeyindex tpmkeyoffset tpmkeysize
    local tkdev tkarg1 tkarg2 tkarg3 resolved extendargs pcrbanklist pcrextendnum pcrextendalg
    local tpmload pcrbank unseal unsealout tpmok noop

    # This file will be loaded by the encrypt hook
    ckeyfile="/crypto_keyfile.bin"

    # Rootfs location for sealed key files
    tpmkeypub="/tpm_keyfile.pub"
    tpmkeypriv="/tpm_keyfile.priv"

    # TPM device
    [ -z $tpmdev ] && tpmdev="/dev/tpmrm0"
    export TPM2TOOLS_ENV_TCTI="device:${tpmdev}"
    export TPM2TOOLS_TCTI_NAME="device"
    export TPM2TOOLS_DEVICE_FILE="$tpmdev"

    # Parse tpmkey command line argument
    if [ -n "$tpmkey" ]; then
        IFS=: read tkdev tkarg1 tkarg2 tkarg3 <<EOF
$tpmkey
EOF
        unset IFS

        case "$tkdev" in
        rootfs)
            # Key is in initcpio root filesystem. Use files in place
            if [ -z "$tkarg3" ]; then
                tpmkeypub="${tkarg1}.pub"
                tpmkeypriv="${tkarg1}.priv"
                tpmkeyparent="$tkarg2"
            else
                tpmkeypub="$tkarg1"
                tpmkeypriv="$tkarg2"
                tpmkeyparent="$tkarg3"
            fi
            ;;
        nvram)
            # Key is in NVRAM. Populate NVRAM variables
            tpmkeyindex="$tkarg1"
            tpmkeyoffset="$tkarg2"
            tpmkeysize="$tkarg3"
            ;;
        *)
            # Key is on block device
            # Locate, mount, and copy the key files
            if resolved=$(resolve_device "${tkdev}" ${rootdelay}); then
                mkdir /tpmkey
                mount -r -t auto "$resolved" /tpmkey

                if [ -z "$tkarg3" ]; then
                    dd if="/tpmkey/${tkarg1}.pub" of="$tpmkeypub" >/dev/null 2>&1
                    dd if="/tpmkey/${tkarg1}.priv" of="$tpmkeypriv" >/dev/null 2>&1
                    tpmkeyparent="$tkarg2"
                else
                    dd if="/tpmkey/${tkarg1}" of="$tpmkeypub" >/dev/null 2>&1
                    dd if="/tpmkey/${tkarg2}" of="$tpmkeypriv" >/dev/null 2>&1
                    tpmkeyparent="$tkarg3"
                fi

                umount /tpmkey
                rmdir /tpmkey
            fi
            ;;
        esac

        # If there is no NVRAM index and no sealed files, print an error
        if [ -z "$tpmkeyindex" ] && [ ! -f "$tpmkeypub" -o ! -f "$tpmkeypriv" ]; then
            err "TPM keyfiles could not be opened"
        fi
    fi

    # Parse the tpmpcr variable
    if [ -n "$tpmpcr" ]; then
        case "$tpmpcr" in
        extend*)
            IFS="|" read extendargs pcrbanklist <<EOF
$tpmpcr
EOF
            IFS=: read noop pcrextendnum pcrextendalg <<EOF
$extendargs
EOF
            unset IFS
            ;;
        *)
            pcrbanklist="$tpmpcr"
            ;;
        esac
    fi

    # We must have a PCR list to retrieve a key
    [ -n "$tpmkey" ] && [ -z "$pcrbanklist" ] && err "TPM PCR bank not specified"


    # If we have a key and PCR list, decrypt it
    if [ -n "$pcrbanklist" -a -n "$tpmkeyindex" ] || [ -n "$pcrbanklist" -a -f "$tpmkeypub" -a -f "$tpmkeypriv" ]; then
        # Load key object if stored on disk
        tpmload=0
        if [ -z "$tpmkeyindex" ]; then
            tpm2_load -Q -H "$tpmkeyparent" -r "$tpmkeypriv" -u "$tpmkeypub" -C /tpmobject.ctx >/dev/null 2>&1
            tpmload=$?
        fi

        # Format nvram arguments
        [ -n "$tpmkeyoffset" ] && tpmkeyoffset="-o ${tpmkeyoffset}"
        [ -n "$tpmkeysize" ] && tpmkeysize="-s ${tpmkeysize}"

        # Attempt to decrypt key with each PCR bank specified
        unseal=1
        if [ $tpmload -eq 0 ]; then
            IFS="|"
            for pcrbank in $pcrbanklist; do
                if [ -n "$tpmkeyindex" ]; then
                    unsealout=$(tpm2_nvread -Q -x "$tpmkeyindex" -a "$tpmkeyindex" $tpmkeyoffset $tpmkeysize -L "$pcrbank" -f $ckeyfile 2>&1)
                    unseal=$?
                else
                    unsealout=$(tpm2_unseal -Q -c /tpmobject.ctx -L "$pcrbank" -o "$ckeyfile" 2>&1)
                    unseal=$?
                fi
                if [ $unseal -eq 0 ]; then break; fi
            done
            unset IFS
        fi

        # Check decryption resuts and report
        tpmok=0
        if [ $unseal -eq 0 ]; then
            tpmok=1
        elif echo "$unsealout" | grep -sqiE 'Could not load tcti'; then
            err "TPM communication error"
        elif echo "$unsealout" | grep -sqiE 'Error.*0x99d'; then
            echo
            echo "!!! TPM WARNING: PCR VALUES HAVE CHANGED !!!"
            echo "This is an indication that the boot configuration has been altered since"
            echo "the TPM key was generated. This is normal after kernel updates or firmware"
            echo "changes, however this could also indicate a malicious change to your system."
            echo
        elif [ -n "$tpmkeyindex" ]; then
            err "Could not read key from TPM NVRAM"
        elif [ $tpmload -ne 0 ]; then
            err "Could not load TPM keyfile"
        else
            err "Could not unseal TPM keyfile"
        fi

        if [ $tpmok -gt 0 ]; then
            msg ":: LUKS key successfully decrypted by TPM"
        else
            rm -f "$ckeyfile"
            msg ":: TPM Could not decrypt LUKS key"
        fi
    fi

    # Extend specified PCR
    if [ -n "$pcrextendnum" ] && [ -n "$pcrextendalg" ]; then
        case "$pcrextendalg" in
        sha1|sha224|sha256|sha384|sha512)
            tpm2_pcrextend ${pcrextendnum}:${pcrextendalg}=$("${pcrextendalg}sum" /hooks/tpm2 2>/dev/null | cut -f1 -d' ') >/dev/null 2>&1
            if [ $? -ne 0 ]; then
                err "Could not extend TPM PCR"
            fi
            ;;
        *)
            err "Hash algorithm not supported for PCR extend"
            ;;
        esac
    fi

    # Cleanup
    rm -f /tpmobject.ctx "$tpmkeypub" "$tpmkeypriv"
}

run_cleanuphook() {
    # Securely delete key if still present
    if [ -f "$ckeyfile" ]; then
        dd if=/dev/urandom of="$ckeyfile" bs=$(stat --printf="%s" "$ckeyfile") count=1 conv=notrunc >/dev/null 2>&1
        rm -f "$ckeyfile"
    fi
}

# vim: set ft=sh ts=4 sw=4 et: