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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
#!/bin/bash
set -eo pipefail
help=$'Generate Tarball with PNOR image and MANIFEST Script
Generates a PNOR SquashFS image from the PNOR image for VPNOR,
Or use a static layout raw PNOR image,
Creates a MANIFEST for image verification and recreation
Packages the image and MANIFEST together in a tarball
usage: generate-tar [OPTION] <PNOR FILE>...
Options:
-i, --image <squashfs|static>
Generate SquashFS image or use static PNOR
-f, --file <file> Specify destination file. Defaults to
`pwd`/<PNOR FILE>.pnor.<image_type>.tar[.gz] if
unspecified.
(For example,
* "generate-tar -i squashfs my.pnor" would generate
`pwd`/my.pnor.squashfs.tar
* "generate-tar -i static my.pnor" would generate
`pwd`/my.pnor.static.tar.gz)
-s, --sign <path> Sign the image. The optional path argument specifies
the private key file. Defaults to the bash variable
PRIVATE_KEY_PATH if available, or else uses the
open-source private key in this script.
-m, --machine <name> Optionally specify the target machine name of this
image.
-h, --help Display this help text and exit.
'
private_key=$'-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPvSDLu6slkP1gri
PaeQXL9ysD69J/HjbBCIQ0RPfeWBb75US1tRTjPP0Ub8CtH8ExVf8iF1ulsZA78B
zIjBYZVp9pyD6LbpZ/hjV7rIH6dTNhoVpdA+F8LzmQ7cyhHG8l2JMvdunwF2uX5k
D4WDcZt/ITKZNQNavPtmIyD5HprdAgMBAAECgYEAuQkTSi5ZNpAoWz76xtGRFSwU
zUT4wQi3Mz6tDtjKTYXasiQGa0dHC1M9F8fDu6BZ9W7W4Dc9hArRcdzEighuxoI/
nZI/0uL89iUEywnDEIHuS6D5JlZaj86/nx9YvQnO8F/seM+MX0EAWVrd5wC7aAF1
h6Fu7ykZB4ggUjQAWwECQQD+AUiDOEO+8btLJ135dQfSGc5VFcZiequnKWVm6uXt
rX771hEYjYMjLqWGFg9G4gE3GuABM5chMINuQQUivy8tAkEA/cxfy19XkjtqcMgE
x/UDt6Nr+Ky/tk+4Y65WxPRDas0uxFOPk/vEjgVmz1k/TAy9G4giisluTvtmltr5
DCLocQJBAJnRHx9PiD7uVhRJz6/L/iNuOzPtTsi+Loq5F83+O6T15qsM1CeBMsOw
cM5FN5UeMcwz+yjfHAsePMkcmMaU7jUCQHlg9+N8upXuIo7Dqj2zOU7nMmkgvSNE
5yuNImRZabC3ZolwaTdd7nf5r1y1Eyec5Ag5yENV6JKPe1Xkbb1XKJECQDngA0h4
6ATvfP1Vrx4CbP11eKXbCsZ9OGPHSgyvVjn68oY5ZP3uPsIattoN7dE2BRfuJm7m
F0nIdUAhR0yTfKM=
-----END PRIVATE KEY-----
'
# Reference the ffs structures at:
# https://github.com/open-power/hostboot/blob/master/src/usr/pnor/common/ffs_hb.H
# https://github.com/open-power/hostboot/blob/master/src/usr/pnor/ffs.h
let ffs_entry_size=128
let vercheck_offset=112
do_sign=false
private_key_path="${PRIVATE_KEY_PATH}"
image_type=""
outfile=""
declare -a partitions=()
tocfile="pnor.toc"
machine_name=""
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-i|--image)
image_type="$2"
shift 2
;;
-f|--file)
outfile="$2"
shift 2
;;
-s|--sign)
do_sign=true
if [[ ! -z "${2}" && "${2}" != -* ]]; then
private_key_path="$2"
shift 2
else
shift 1
fi
;;
-m|--machine)
machine_name="$2"
shift 2
;;
-h|--help)
echo "$help"
exit
;;
*)
pnorfile="$1"
shift 1
;;
esac
done
if [ ! -f "${pnorfile}" ]; then
echo "Please enter a valid PNOR file."
echo "$help"
exit 1
fi
if [[ "${image_type}" == "squashfs" ]]; then
echo "Will generate squashfs image for VPNOR"
elif [[ "${image_type}" == "static" ]]; then
echo "Will use static image for PNOR"
else
echo "Please specify the image type, \"squashfs\" or \"static\""
echo
echo "$help"
exit 1
fi
if [[ -z $outfile ]]; then
if [[ ${pnorfile##*.} == "pnor" ]]; then
outfile=`pwd`/${pnorfile##*/}.$image_type.tar
else
outfile=`pwd`/${pnorfile##*/}.pnor.$image_type.tar
fi
if [[ "${image_type}" == "static" ]]; then
# Append .gz so the tarball is compressed
outfile=$outfile.gz
fi
else
if [[ $outfile != /* ]]; then
outfile=`pwd`/$outfile
fi
fi
scratch_dir=`mktemp -d`
# Remove the temp directory on exit.
# The files in the temp directory may contain read-only files, so add
# --interactive=never to skip the prompt.
trap "{ rm -r --interactive=never ${scratch_dir}; }" EXIT
if [[ "${do_sign}" == true ]]; then
if [[ -z "${private_key_path}" ]]; then
private_key_path=${scratch_dir}/OpenBMC.priv
echo "${private_key}" > "${private_key_path}"
echo "Image is NOT secure!! Signing with the open private key!"
else
if [[ ! -f "${private_key_path}" ]]; then
echo "Couldn't find private key ${private_key_path}."
exit 1
fi
echo "Signing with ${private_key_path}."
fi
public_key_file=publickey
public_key_path=${scratch_dir}/$public_key_file
openssl pkey -in "${private_key_path}" -pubout -out ${public_key_path}
fi
echo "Parsing PNOR TOC..."
pnor_dir="${scratch_dir}/pnor"
mkdir ${pnor_dir}
pflash --partition=part --read=${pnor_dir}/part -F ${pnorfile}
pflash --partition=VERSION --read=${pnor_dir}/VERSION -F ${pnorfile}
version_size=$(wc -c ${pnor_dir}/VERSION | cut -d' ' -f 1)
magic_number=$(xxd -p -l 4 ${pnor_dir}/VERSION)
# Check if VERSION is signed. A signed version partition will have an extra
# 4K header starting with the magic number 0x17082011, see:
# https://github.com/open-power/skiboot/blob/master/libstb/container.h#L47
if [ "$version_size" == "8192" -a "$magic_number" == "17082011" ]; then
# Advance past the STB header (4K, indexed from 1)
cp ${pnor_dir}/VERSION ${pnor_dir}/VERSION_FULL
tail --bytes=+4097 ${pnor_dir}/VERSION_FULL > ${pnor_dir}/VERSION
fi
{
version=$(head -n 1 ${pnor_dir}/VERSION)
echo "version=$version"
extended_version=$(echo $(tail -n +2 ${pnor_dir}/VERSION)|tr ' ' ',')
echo "extended_version=$extended_version"
while read line; do
if [[ $line == "ID="* ]]; then
# This line looks like
# "ID=05 MVPD 000d9000..00169000 (actual=00090000) [ECC]"
read -r -a fields <<< "$line"
id=${fields[0]##*=}
offset=$((${ffs_entry_size} * 10#${id} + ${vercheck_offset}))
vercheck=$(xxd -p -l 0x1 -seek ${offset} ${pnor_dir}/part)
export flags=$(pflash --detail=$((10#$id)) -F ${pnorfile} | grep "\[" |
sed 's/....$//' | tr '\n' ',' | sed 's/.$//')
if [[ $flags != "" ]]; then
flags=,$flags
fi
if [[ $(echo $flags | grep "READONLY") == "" &&
$(echo $flags | grep "PRESERVED") == "" ]]; then
flags=$flags,READWRITE
fi
# Need the partition ID, name, start location, end location, and flags
echo "partition${id}=${fields[1]},${fields[2]/../,},${vercheck}${flags}"
# Save the partition name
partitions+=(${fields[1]})
fi
# Don't need the BACKUP_PART partition
done < <(pflash --info -F ${pnorfile} | grep -v "BACKUP")
} > ${pnor_dir}/${tocfile}
for partition in "${partitions[@]}"; do
echo "Reading ${partition}..."
pflash --partition=${partition} \
--read=${pnor_dir}/${partition} \
-F ${pnorfile}
done
manifest_location="MANIFEST"
files_to_sign="$manifest_location $public_key_file"
# Go to scratch_dir
if [[ "${image_type}" == "squashfs" ]]; then
echo "Creating SquashFS image..."
# Prepare pnor file in ${pnor_dir}
cd "${pnor_dir}"
# Set permissions of partition files to read only
chmod 440 *
mksquashfs ${tocfile} ${partitions[*]} ${scratch_dir}/pnor.xz.squashfs -all-root
cd "${scratch_dir}"
files_to_sign+=" pnor.xz.squashfs"
else
cp ${pnorfile} ${scratch_dir}
cd "${scratch_dir}"
files_to_sign+=" $(basename ${pnorfile})"
fi
echo "Creating MANIFEST for the image"
echo -e "purpose=xyz.openbmc_project.Software.Version.VersionPurpose.Host\nversion=$version\n\
extended_version=$extended_version" >> $manifest_location
if [[ ! -z "${machine_name}" ]]; then
echo -e "MachineName=${machine_name}" >> $manifest_location
fi
if [[ "${do_sign}" == true ]]; then
private_key_name=$(basename "${private_key_path}")
key_type="${private_key_name%.*}"
echo KeyType="${key_type}" >> $manifest_location
echo HashType="RSA-SHA256" >> $manifest_location
for file in $files_to_sign; do
openssl dgst -sha256 -sign ${private_key_path} -out "${file}.sig" $file
done
additional_files="*.sig"
fi
if [[ "${image_type}" == "squashfs" ]]; then
echo "Generating tarball to contain the SquashFS image and its MANIFEST"
tar -cvf $outfile $files_to_sign $additional_files
echo "SquashFSTarball at ${outfile}"
else
tar -czvf $outfile $files_to_sign $additional_files
echo "Static layout tarball at $outfile"
fi
|