1#!/bin/bash -eux
2# Copyright 2014 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6me=${0##*/}
7TMP="$me.tmp"
8
9# Work in scratch directory
10cd "$OUTDIR"
11
12# Helper utility to modify binary blobs
13REPLACE="${BUILD_RUN}/tests/futility/binary_editor"
14
15# First, let's test the basic functionality
16
17# For simplicity, we'll use the same size for all properties.
18${FUTILITY} gbb_utility -c 16,0x10,16,0x10 ${TMP}.blob
19
20# Flags
21${FUTILITY} gbb_utility -s --flags=0xdeadbeef ${TMP}.blob
22${FUTILITY} gbb_utility -g --flags ${TMP}.blob | grep -i 0xdeadbeef
23
24# HWID length should include the terminating null - this is too long
25if ${FUTILITY} gbb_utility -s --hwid="0123456789ABCDEF" ${TMP}.blob; then
26  false;
27fi
28# This works
29${FUTILITY} gbb_utility -s --hwid="0123456789ABCDE" ${TMP}.blob
30# Read it back?
31${FUTILITY} gbb_utility -g ${TMP}.blob | grep "0123456789ABCDE"
32
33# Same kind of tests for the other fields, but they need binary files.
34
35# too long
36dd if=/dev/urandom bs=17 count=1 of=${TMP}.data1.toolong
37dd if=/dev/urandom bs=17 count=1 of=${TMP}.data2.toolong
38dd if=/dev/urandom bs=17 count=1 of=${TMP}.data3.toolong
39if ${FUTILITY} gbb_utility -s --rootkey     ${TMP}.data1.toolong ${TMP}.blob; then false; fi
40if ${FUTILITY} gbb_utility -s --recoverykey ${TMP}.data2.toolong ${TMP}.blob; then false; fi
41if ${FUTILITY} gbb_utility -s --bmpfv       ${TMP}.data3.toolong ${TMP}.blob; then false; fi
42
43# shorter than max should be okay, though
44dd if=/dev/urandom bs=10 count=1 of=${TMP}.data1.short
45dd if=/dev/urandom bs=10 count=1 of=${TMP}.data2.short
46dd if=/dev/urandom bs=10 count=1 of=${TMP}.data3.short
47${FUTILITY} gbb_utility -s \
48  --rootkey     ${TMP}.data1.short \
49  --recoverykey ${TMP}.data2.short \
50  --bmpfv       ${TMP}.data3.short ${TMP}.blob
51# read 'em back
52${FUTILITY} gbb_utility -g \
53  --rootkey     ${TMP}.read1 \
54  --recoverykey ${TMP}.read2 \
55  --bmpfv       ${TMP}.read3 ${TMP}.blob
56# Verify (but remember, it's short)
57cmp -n 10 ${TMP}.data1.short ${TMP}.read1
58cmp -n 10 ${TMP}.data2.short ${TMP}.read2
59cmp -n 10 ${TMP}.data3.short ${TMP}.read3
60
61# Okay
62dd if=/dev/urandom bs=16 count=1 of=${TMP}.data1
63dd if=/dev/urandom bs=16 count=1 of=${TMP}.data2
64dd if=/dev/urandom bs=16 count=1 of=${TMP}.data3
65${FUTILITY} gbb_utility -s --rootkey     ${TMP}.data1 ${TMP}.blob
66${FUTILITY} gbb_utility -s --recoverykey ${TMP}.data2 ${TMP}.blob
67${FUTILITY} gbb_utility -s --bmpfv       ${TMP}.data3 ${TMP}.blob
68
69# Read 'em back.
70${FUTILITY} gbb_utility -g --rootkey     ${TMP}.read1 ${TMP}.blob
71${FUTILITY} gbb_utility -g --recoverykey ${TMP}.read2 ${TMP}.blob
72${FUTILITY} gbb_utility -g --bmpfv       ${TMP}.read3 ${TMP}.blob
73# Verify
74cmp ${TMP}.data1 ${TMP}.read1
75cmp ${TMP}.data2 ${TMP}.read2
76cmp ${TMP}.data3 ${TMP}.read3
77
78
79# Okay, creating GBB blobs seems to work. Now let's make sure that corrupted
80# blobs are rejected.
81
82# Danger Will Robinson! We assume that ${TMP}.blob has this binary struct:
83#
84# Field                 Offset  Value
85#
86# signature:            0x0000  $GBB
87# major_version:        0x0004  0x0001
88# minor_version:        0x0006  0x0001
89# header_size:          0x0008  0x00000080
90# flags:                0x000c  0xdeadbeef
91# hwid_offset:          0x0010  0x00000080
92# hwid_size:            0x0014  0x00000010
93# rootkey_offset:       0x0018  0x00000090
94# rootkey_size:         0x001c  0x00000010
95# bmpfv_offset:         0x0020  0x000000a0
96# bmpfv_size:           0x0024  0x00000010
97# recovery_key_offset:  0x0028  0x000000b0
98# recovery_key_size:    0x002c  0x00000010
99# pad:                  0x0030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
100#                       0x0040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
101#                       0x0050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
102#                       0x0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
103#                       0x0070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
104# (HWID)                0x0080  30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 00
105# (rootkey)             0x0090  xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
106# (bmpfv)               0x00a0  xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
107# (recovery_key)        0x00b0  xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
108#                       0x00c0  <EOF>
109#
110
111# bad major_version
112cat ${TMP}.blob | ${REPLACE} 0x4 2 > ${TMP}.blob.bad
113if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
114
115# header size too large
116cat ${TMP}.blob | ${REPLACE} 0x8 0x81 > ${TMP}.blob.bad
117if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
118
119# header size too small
120cat ${TMP}.blob | ${REPLACE} 0x8 0x7f > ${TMP}.blob.bad
121if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
122
123# HWID not null-terminated is invalid
124cat ${TMP}.blob | ${REPLACE} 0x8f 0x41 > ${TMP}.blob.bad
125if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
126
127# HWID of length zero is okay
128cat ${TMP}.blob | ${REPLACE} 0x14 0x00 > ${TMP}.blob.ok
129${FUTILITY} gbb_utility ${TMP}.blob.ok
130# And HWID of length 1 consisting only of '\0' is okay, too.
131cat ${TMP}.blob | ${REPLACE} 0x14 0x01 | ${REPLACE} 0x80 0x00 > ${TMP}.blob.ok
132${FUTILITY} gbb_utility ${TMP}.blob.ok
133
134# zero-length HWID not null-terminated is invalid
135cat ${TMP}.blob | ${REPLACE} 0x8f 0x41 > ${TMP}.blob.bad
136if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
137
138#  hwid_offset < GBB_HEADER_SIZE is invalid
139cat ${TMP}.blob | ${REPLACE} 0x10 0x7f > ${TMP}.blob.bad
140if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
141cat ${TMP}.blob | ${REPLACE} 0x10 0x00 > ${TMP}.blob.bad
142if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
143
144#  rootkey_offset < GBB_HEADER_SIZE is invalid
145cat ${TMP}.blob | ${REPLACE} 0x18 0x7f > ${TMP}.blob.bad
146if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
147cat ${TMP}.blob | ${REPLACE} 0x18 0x00 > ${TMP}.blob.bad
148if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
149
150#  bmpfv_offset < GBB_HEADER_SIZE is invalid
151cat ${TMP}.blob | ${REPLACE} 0x20 0x7f > ${TMP}.blob.bad
152if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
153cat ${TMP}.blob | ${REPLACE} 0x20 0x00 > ${TMP}.blob.bad
154if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
155
156#  recovery_key_offset < GBB_HEADER_SIZE is invalid
157cat ${TMP}.blob | ${REPLACE} 0x28 0x7f > ${TMP}.blob.bad
158if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
159cat ${TMP}.blob | ${REPLACE} 0x28 0x00 > ${TMP}.blob.bad
160if ${FUTILITY} gbb_utility ${TMP}.blob.bad; then false; fi
161
162#  hwid: offset + size  == end of file is okay; beyond is invalid
163cat ${TMP}.blob | ${REPLACE} 0x14 0x40 > ${TMP}.blob.bad
164${FUTILITY} gbb_utility -g ${TMP}.blob.bad
165cat ${TMP}.blob | ${REPLACE} 0x14 0x41 > ${TMP}.blob.bad
166if ${FUTILITY} gbb_utility -g ${TMP}.blob.bad; then false; fi
167
168#  rootkey: offset + size  == end of file is okay; beyond is invalid
169cat ${TMP}.blob | ${REPLACE} 0x1c 0x30 > ${TMP}.blob.bad
170${FUTILITY} gbb_utility -g ${TMP}.blob.bad
171cat ${TMP}.blob | ${REPLACE} 0x1c 0x31 > ${TMP}.blob.bad
172if ${FUTILITY} gbb_utility -g ${TMP}.blob.bad; then false; fi
173
174#  bmpfv: offset + size  == end of file is okay; beyond is invalid
175cat ${TMP}.blob | ${REPLACE} 0x24 0x20 > ${TMP}.blob.bad
176${FUTILITY} gbb_utility -g ${TMP}.blob.bad
177cat ${TMP}.blob | ${REPLACE} 0x24 0x21 > ${TMP}.blob.bad
178if ${FUTILITY} gbb_utility -g ${TMP}.blob.bad; then false; fi
179
180#  recovery_key: offset + size  == end of file is okay; beyond is invalid
181cat ${TMP}.blob | ${REPLACE} 0x2c 0x10 > ${TMP}.blob.bad
182${FUTILITY} gbb_utility -g ${TMP}.blob.bad
183cat ${TMP}.blob | ${REPLACE} 0x2c 0x11 > ${TMP}.blob.bad
184if ${FUTILITY} gbb_utility -g ${TMP}.blob.bad; then false; fi
185
186# hwid_size == 0 doesn't complain, but can't be set
187cat ${TMP}.blob | ${REPLACE} 0x14 0x00 > ${TMP}.blob.bad
188${FUTILITY} gbb_utility -g ${TMP}.blob.bad
189if ${FUTILITY} gbb_utility -s --hwid="A" ${TMP}.blob.bad; then false; fi
190
191# rootkey_size == 0 gives warning, gets nothing, can't be set
192cat ${TMP}.blob | ${REPLACE} 0x1c 0x00 > ${TMP}.blob.bad
193${FUTILITY} gbb_utility -g --rootkey     ${TMP}.read1 ${TMP}.blob.bad
194if ${FUTILITY} gbb_utility -s --rootkey  ${TMP}.data1 ${TMP}.blob.bad; then false; fi
195
196# bmpfv_size == 0 gives warning, gets nothing, can't be set
197cat ${TMP}.blob | ${REPLACE} 0x24 0x00 > ${TMP}.blob.bad
198${FUTILITY} gbb_utility -g --bmpfv       ${TMP}.read3 ${TMP}.blob.bad
199if ${FUTILITY} gbb_utility -s --bmpfv    ${TMP}.data3 ${TMP}.blob.bad; then false; fi
200
201# recovery_key_size == 0 gives warning, gets nothing, can't be set
202cat ${TMP}.blob | ${REPLACE} 0x2c 0x00 > ${TMP}.blob.bad
203${FUTILITY} gbb_utility -g --recoverykey ${TMP}.read2 ${TMP}.blob.bad
204if ${FUTILITY} gbb_utility -s --recoverykey ${TMP}.data2 ${TMP}.blob.bad; then false; fi
205
206
207# GBB v1.2 adds a sha256 digest field in what was previously padding:
208#
209# hwid_digest:          0x0030  xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
210#                       0x0040  xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
211# pad:                  0x0050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
212#                       0x0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
213#                       0x0070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
214# (HWID)                0x0080  30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 00
215
216# See that the digest is updated properly.
217hwid="123456789ABCDEF"
218${FUTILITY} gbb_utility -s --hwid=${hwid} ${TMP}.blob
219expect=$(echo -n "$hwid" | sha256sum | cut -d ' ' -f 1)
220[ $(echo -n ${expect} | wc -c) == "64" ]
221${FUTILITY} gbb_utility -g --digest ${TMP}.blob | grep ${expect}
222
223# Garble the digest, see that it's noticed.
224# (assuming these zeros aren't present)
225cat ${TMP}.blob | ${REPLACE} 0x33 0x00 0x00 0x00 0x00 0x00 > ${TMP}.blob.bad
226${FUTILITY} gbb_utility -g --digest ${TMP}.blob.bad | grep '0000000000'
227${FUTILITY} gbb_utility -g --digest ${TMP}.blob.bad | grep 'invalid'
228
229# Garble the HWID. The digest is unchanged, but now invalid.
230cat ${TMP}.blob | ${REPLACE} 0x84 0x70 0x71 0x72 > ${TMP}.blob.bad
231${FUTILITY} gbb_utility -g --digest ${TMP}.blob.bad | grep 'invalid'
232
233# cleanup
234rm -f ${TMP}*
235exit 0
236