1 /* 2 * Copyright (c) 2013, Google Inc. 3 * 4 * (C) Copyright 2008 Semihalf 5 * 6 * (C) Copyright 2000-2006 7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 8 * 9 * See file CREDITS for list of people who contributed to this 10 * project. 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License as 14 * published by the Free Software Foundation; either version 2 of 15 * the License, or (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 25 * MA 02111-1307 USA 26 */ 27 28 #include "mkimage.h" 29 #include <image.h> 30 #include <version.h> 31 32 /** 33 * fit_set_hash_value - set hash value in requested has node 34 * @fit: pointer to the FIT format image header 35 * @noffset: hash node offset 36 * @value: hash value to be set 37 * @value_len: hash value length 38 * 39 * fit_set_hash_value() attempts to set hash value in a node at offset 40 * given and returns operation status to the caller. 41 * 42 * returns 43 * 0, on success 44 * -1, on failure 45 */ 46 static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, 47 int value_len) 48 { 49 int ret; 50 51 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 52 if (ret) { 53 printf("Can't set hash '%s' property for '%s' node(%s)\n", 54 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), 55 fdt_strerror(ret)); 56 return -1; 57 } 58 59 return 0; 60 } 61 62 /** 63 * fit_image_process_hash - Process a single subnode of the images/ node 64 * 65 * Check each subnode and process accordingly. For hash nodes we generate 66 * a hash of the supplised data and store it in the node. 67 * 68 * @fit: pointer to the FIT format image header 69 * @image_name: name of image being processes (used to display errors) 70 * @noffset: subnode offset 71 * @data: data to process 72 * @size: size of data in bytes 73 * @return 0 if ok, -1 on error 74 */ 75 static int fit_image_process_hash(void *fit, const char *image_name, 76 int noffset, const void *data, size_t size) 77 { 78 uint8_t value[FIT_MAX_HASH_LEN]; 79 const char *node_name; 80 int value_len; 81 char *algo; 82 83 node_name = fit_get_name(fit, noffset, NULL); 84 85 if (fit_image_hash_get_algo(fit, noffset, &algo)) { 86 printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 87 node_name, image_name); 88 return -1; 89 } 90 91 if (calculate_hash(data, size, algo, value, &value_len)) { 92 printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 93 algo, node_name, image_name); 94 return -1; 95 } 96 97 if (fit_set_hash_value(fit, noffset, value, value_len)) { 98 printf("Can't set hash value for '%s' hash node in '%s' image node\n", 99 node_name, image_name); 100 return -1; 101 } 102 103 return 0; 104 } 105 106 /** 107 * fit_image_write_sig() - write the signature to a FIT 108 * 109 * This writes the signature and signer data to the FIT. 110 * 111 * @fit: pointer to the FIT format image header 112 * @noffset: hash node offset 113 * @value: signature value to be set 114 * @value_len: signature value length 115 * @comment: Text comment to write (NULL for none) 116 * 117 * returns 118 * 0, on success 119 * -FDT_ERR_..., on failure 120 */ 121 static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, 122 int value_len, const char *comment, const char *region_prop, 123 int region_proplen) 124 { 125 int string_size; 126 int ret; 127 128 /* 129 * Get the current string size, before we update the FIT and add 130 * more 131 */ 132 string_size = fdt_size_dt_strings(fit); 133 134 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 135 if (!ret) { 136 ret = fdt_setprop_string(fit, noffset, "signer-name", 137 "mkimage"); 138 } 139 if (!ret) { 140 ret = fdt_setprop_string(fit, noffset, "signer-version", 141 PLAIN_VERSION); 142 } 143 if (comment && !ret) 144 ret = fdt_setprop_string(fit, noffset, "comment", comment); 145 if (!ret) 146 ret = fit_set_timestamp(fit, noffset, time(NULL)); 147 if (region_prop && !ret) { 148 uint32_t strdata[2]; 149 150 ret = fdt_setprop(fit, noffset, "hashed-nodes", 151 region_prop, region_proplen); 152 strdata[0] = 0; 153 strdata[1] = cpu_to_fdt32(string_size); 154 if (!ret) { 155 ret = fdt_setprop(fit, noffset, "hashed-strings", 156 strdata, sizeof(strdata)); 157 } 158 } 159 160 return ret; 161 } 162 163 static int fit_image_setup_sig(struct image_sign_info *info, 164 const char *keydir, void *fit, const char *image_name, 165 int noffset, const char *require_keys) 166 { 167 const char *node_name; 168 char *algo_name; 169 170 node_name = fit_get_name(fit, noffset, NULL); 171 if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { 172 printf("Can't get algo property for '%s' signature node in '%s' image node\n", 173 node_name, image_name); 174 return -1; 175 } 176 177 memset(info, '\0', sizeof(*info)); 178 info->keydir = keydir; 179 info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 180 info->fit = fit; 181 info->node_offset = noffset; 182 info->algo = image_get_sig_algo(algo_name); 183 info->require_keys = require_keys; 184 if (!info->algo) { 185 printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", 186 algo_name, node_name, image_name); 187 return -1; 188 } 189 190 return 0; 191 } 192 193 /** 194 * fit_image_process_sig- Process a single subnode of the images/ node 195 * 196 * Check each subnode and process accordingly. For signature nodes we 197 * generate a signed hash of the supplised data and store it in the node. 198 * 199 * @keydir: Directory containing keys to use for signing 200 * @keydest: Destination FDT blob to write public keys into 201 * @fit: pointer to the FIT format image header 202 * @image_name: name of image being processes (used to display errors) 203 * @noffset: subnode offset 204 * @data: data to process 205 * @size: size of data in bytes 206 * @comment: Comment to add to signature nodes 207 * @require_keys: Mark all keys as 'required' 208 * @return 0 if ok, -1 on error 209 */ 210 static int fit_image_process_sig(const char *keydir, void *keydest, 211 void *fit, const char *image_name, 212 int noffset, const void *data, size_t size, 213 const char *comment, int require_keys) 214 { 215 struct image_sign_info info; 216 struct image_region region; 217 const char *node_name; 218 uint8_t *value; 219 uint value_len; 220 int ret; 221 222 if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, 223 require_keys ? "image" : NULL)) 224 return -1; 225 226 node_name = fit_get_name(fit, noffset, NULL); 227 region.data = data; 228 region.size = size; 229 ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); 230 if (ret) { 231 printf("Failed to sign '%s' signature node in '%s' image node: %d\n", 232 node_name, image_name, ret); 233 234 /* We allow keys to be missing */ 235 if (ret == -ENOENT) 236 return 0; 237 return -1; 238 } 239 240 ret = fit_image_write_sig(fit, noffset, value, value_len, comment, 241 NULL, 0); 242 if (ret) { 243 printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", 244 node_name, image_name, fdt_strerror(ret)); 245 return -1; 246 } 247 free(value); 248 249 /* Get keyname again, as FDT has changed and invalidated our pointer */ 250 info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); 251 252 /* Write the public key into the supplied FDT file */ 253 if (keydest && info.algo->add_verify_data(&info, keydest)) { 254 printf("Failed to add verification data for '%s' signature node in '%s' image node\n", 255 node_name, image_name); 256 return -1; 257 } 258 259 return 0; 260 } 261 262 /** 263 * fit_image_add_verification_data() - calculate/set verig. data for image node 264 * 265 * This adds hash and signature values for an component image node. 266 * 267 * All existing hash subnodes are checked, if algorithm property is set to 268 * one of the supported hash algorithms, hash value is computed and 269 * corresponding hash node property is set, for example: 270 * 271 * Input component image node structure: 272 * 273 * o image@1 (at image_noffset) 274 * | - data = [binary data] 275 * o hash@1 276 * |- algo = "sha1" 277 * 278 * Output component image node structure: 279 * 280 * o image@1 (at image_noffset) 281 * | - data = [binary data] 282 * o hash@1 283 * |- algo = "sha1" 284 * |- value = sha1(data) 285 * 286 * For signature details, please see doc/uImage.FIT/signature.txt 287 * 288 * @keydir Directory containing *.key and *.crt files (or NULL) 289 * @keydest FDT Blob to write public keys into (NULL if none) 290 * @fit: Pointer to the FIT format image header 291 * @image_noffset: Requested component image node 292 * @comment: Comment to add to signature nodes 293 * @require_keys: Mark all keys as 'required' 294 * @return: 0 on success, <0 on failure 295 */ 296 int fit_image_add_verification_data(const char *keydir, void *keydest, 297 void *fit, int image_noffset, const char *comment, 298 int require_keys) 299 { 300 const char *image_name; 301 const void *data; 302 size_t size; 303 int noffset; 304 305 /* Get image data and data length */ 306 if (fit_image_get_data(fit, image_noffset, &data, &size)) { 307 printf("Can't get image data/size\n"); 308 return -1; 309 } 310 311 image_name = fit_get_name(fit, image_noffset, NULL); 312 313 /* Process all hash subnodes of the component image node */ 314 for (noffset = fdt_first_subnode(fit, image_noffset); 315 noffset >= 0; 316 noffset = fdt_next_subnode(fit, noffset)) { 317 const char *node_name; 318 int ret = 0; 319 320 /* 321 * Check subnode name, must be equal to "hash" or "signature". 322 * Multiple hash nodes require unique unit node 323 * names, e.g. hash@1, hash@2, signature@1, etc. 324 */ 325 node_name = fit_get_name(fit, noffset, NULL); 326 if (!strncmp(node_name, FIT_HASH_NODENAME, 327 strlen(FIT_HASH_NODENAME))) { 328 ret = fit_image_process_hash(fit, image_name, noffset, 329 data, size); 330 } else if (IMAGE_ENABLE_SIGN && keydir && 331 !strncmp(node_name, FIT_SIG_NODENAME, 332 strlen(FIT_SIG_NODENAME))) { 333 ret = fit_image_process_sig(keydir, keydest, 334 fit, image_name, noffset, data, size, 335 comment, require_keys); 336 } 337 if (ret) 338 return -1; 339 } 340 341 return 0; 342 } 343 344 int fit_add_verification_data(const char *keydir, void *keydest, void *fit, 345 const char *comment, int require_keys) 346 { 347 int images_noffset; 348 int noffset; 349 int ret; 350 351 /* Find images parent node offset */ 352 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 353 if (images_noffset < 0) { 354 printf("Can't find images parent node '%s' (%s)\n", 355 FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 356 return images_noffset; 357 } 358 359 /* Process its subnodes, print out component images details */ 360 for (noffset = fdt_first_subnode(fit, images_noffset); 361 noffset >= 0; 362 noffset = fdt_next_subnode(fit, noffset)) { 363 /* 364 * Direct child node of the images parent node, 365 * i.e. component image node. 366 */ 367 ret = fit_image_add_verification_data(keydir, keydest, 368 fit, noffset, comment, require_keys); 369 if (ret) 370 return ret; 371 } 372 373 return 0; 374 } 375