summarylogtreecommitdiffstats
path: root/nannycam
blob: 064190f2aab53b0a946306026499b18d600c1736 (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
#!/bin/ash

set -u
set -e
# set -x

usage () {
  cat <<HELPEOF
  nannycam -k keyfile -m hash -p hash [-e hash]

    -k Signing Key
    -m Expected MBR hash
    -p Expected Post-MBR Gap hash
    -e Expected EFI Stub hash
  
  nannycam helps protect against Evil Maid attacks against encrypted boot partitions.
  First, nannycam hashes the MBR, Post-MBR gap, and (optionally) the named EFI stub
  and compares them against expected values. Next, nannycam uses a private key to
  sign the current date and time. It is expected that this key be stored inside the
  encrypted boot partition. The signature is displayed as a QR code so that another
  device can verify that the signature is valid and the date/time signed is recent.

  If any of the hashes do not match, the boot process is paused. An error message is
  displayed advising the user NOT to enter their root device encryption passphrase.
  If the user feels there has been a misconfiguration, the user can continue the boot
  sequence (potentially exposing their root encryption passphrase in the process).

  The user must type (in uppercase) YES to continue the boot sequence after verifying
  the date/time signature. If the signature does not validate, it is possible that 
  the entire encrypted boot partition has been replaced with one that was crafted to
  appear similar but might record and/or transmit the root encryption passphrase.

  Presumably, if the encryption of the boot partition is secure, then the key stored
  inside the encrypted boot partition cannot be known by an attacker. This prevents
  wholesale replacement of the entire boot partition. Hashes taken of the MBR, Post-
  MBR Gap, and EFI Stub assist in protecting against attackers replacing them in an
  attempt to record the boot partition's encryption passphrase and subsequently 
  extracting the private key material used to authenticate the boot partition.

  nannycam does not prevent all Evil Maid attacks. It is of course possible for state
  actors to launch hardware-level attacks, but even less powerful adversaries may be
  clever enough to thwart these protections.
HELPEOF
}


err_required_arg () {
  echo "-$1 is a required option" >&2
  exit 1
}

hash_mismatch () {
  (cat <<WARNEOF
*****************************************************************
* WARNING: Unexpected hash. Do NOT enter root device passphrase *
*****************************************************************

There was a mismatch in the expected and actual hash values for
critical boot programs. Either a misconfiguration has occurred or
a malicious actor has modified this programs. It is advised that
you restore the MBR, Post MBR Gap, and (if using EFI) the EFI Stub
from secure backups. Do NOT enter your root device passphrase 
unless you are certain this is a misconfiguration.

         Expected Hash      Actual Hash
MBR      $EXPECTED_MBR_HASH $ACTUAL_MBR_HASH
MBR Gap  $EXPECTED_MBR_GAP_HASH $ACTUAL_MBR_GAP_HASH
EFI Stub $EXPECTED_EFI_STUB_HASH $ACTUAL_EFI_STUB_HASH

WARNEOF
) >&2

  local response=""
  while [[ "$response" != "YES" ]]; do
    read -p "Enter YES to continue booting (not recommended): " response
  done
}

check_mbr () {
  echo "TODO: Calculate MBR HASH"
}

check_mbr_gap () {
  echo "TODO: Calculate MBR Gap Hash"
}

check_efi_stub () {
  echo "TODO: Check EFI Stub hash"
}

while getopts ":k:m:p:e:" opt; do
  case $opt in
    k)
      KEYFILE="$OPTARG"
      ;;
    m)
      EXPECTED_MBR_HASH="$OPTARG"
      ;;
    p)
      EXPECTED_MBR_GAP_HASH="$OPTARG"
      ;;
    e)
      EXPECTED_EFI_STUB_HASH="$OPTARG"
      ;;
    \?)
      usage >&2
      exit 1
      ;;
    :)
      echo "$OPTARG requires an argument" >&2
      exit 1
  esac
done

[ -z ${KEYFILE:-} ] && err_required_arg k
[ -z ${EXPECTED_MBR_HASH:-} ] && err_required_arg m
[ -z ${EXPECTED_MBR_GAP_HASH:-} ] && err_required_arg p
[ -z ${EXPECTED_EFI_STUB_HASH:-} ] && err_required_arg e

ACTUAL_MBR_HASH="not checked"
ACTUAL_MBR_GAP_HASH="not checked"
ACTUAL_EFI_STUB_HASH="not checked"

if [ ! -f "$KEYFILE" ]; then
  echo "Keyfile: $KEYFILE not found, aborting boot." >&2
  exit 2
fi

check_mbr || hash_mismatch
check_mbr_gap || hash_mismatch
check_efi_stub || hash_mismatch

DATE_TIME="$(date +%s)"
echo -n "$DATE_TIME" | openssl pkeyutl -inkey "$KEYFILE" -sign | qrencode -t UTF8 -m0
echo "$DATE_TIME"

response=""
while [[ "$response" != "YES" ]]; do
  read -p "Enter YES if the signature is correct: " response
done