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