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 <bootstage.h> 30 #include <image.h> 31 #include <sha1.h> 32 #include <time.h> 33 #include <u-boot/crc.h> 34 #include <u-boot/md5.h> 35 36 /** 37 * fit_set_hash_value - set hash value in requested has node 38 * @fit: pointer to the FIT format image header 39 * @noffset: hash node offset 40 * @value: hash value to be set 41 * @value_len: hash value length 42 * 43 * fit_set_hash_value() attempts to set hash value in a node at offset 44 * given and returns operation status to the caller. 45 * 46 * returns 47 * 0, on success 48 * -1, on failure 49 */ 50 static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, 51 int value_len) 52 { 53 int ret; 54 55 ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); 56 if (ret) { 57 printf("Can't set hash '%s' property for '%s' node(%s)\n", 58 FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), 59 fdt_strerror(ret)); 60 return -1; 61 } 62 63 return 0; 64 } 65 66 /** 67 * fit_image_process_hash - Process a single subnode of the images/ node 68 * 69 * Check each subnode and process accordingly. For hash nodes we generate 70 * a hash of the supplised data and store it in the node. 71 * 72 * @fit: pointer to the FIT format image header 73 * @image_name: name of image being processes (used to display errors) 74 * @noffset: subnode offset 75 * @data: data to process 76 * @size: size of data in bytes 77 * @return 0 if ok, -1 on error 78 */ 79 static int fit_image_process_hash(void *fit, const char *image_name, 80 int noffset, const void *data, size_t size) 81 { 82 uint8_t value[FIT_MAX_HASH_LEN]; 83 const char *node_name; 84 int value_len; 85 char *algo; 86 87 node_name = fit_get_name(fit, noffset, NULL); 88 89 if (fit_image_hash_get_algo(fit, noffset, &algo)) { 90 printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", 91 node_name, image_name); 92 return -1; 93 } 94 95 if (calculate_hash(data, size, algo, value, &value_len)) { 96 printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", 97 algo, node_name, image_name); 98 return -1; 99 } 100 101 if (fit_set_hash_value(fit, noffset, value, value_len)) { 102 printf("Can't set hash value for '%s' hash node in '%s' image node\n", 103 node_name, image_name); 104 return -1; 105 } 106 107 return 0; 108 } 109 110 /** 111 * fit_image_add_verification_data() - calculate/set hash data for image node 112 * 113 * This adds hash values for a component image node. 114 * 115 * All existing hash subnodes are checked, if algorithm property is set to 116 * one of the supported hash algorithms, hash value is computed and 117 * corresponding hash node property is set, for example: 118 * 119 * Input component image node structure: 120 * 121 * o image@1 (at image_noffset) 122 * | - data = [binary data] 123 * o hash@1 124 * |- algo = "sha1" 125 * 126 * Output component image node structure: 127 * 128 * o image@1 (at image_noffset) 129 * | - data = [binary data] 130 * o hash@1 131 * |- algo = "sha1" 132 * |- value = sha1(data) 133 * 134 * For signature details, please see doc/uImage.FIT/signature.txt 135 * 136 * @fit: Pointer to the FIT format image header 137 * @image_noffset: Requested component image node 138 * @return: 0 on success, <0 on failure 139 */ 140 int fit_image_add_verification_data(void *fit, int image_noffset) 141 { 142 const char *image_name; 143 const void *data; 144 size_t size; 145 int noffset; 146 147 /* Get image data and data length */ 148 if (fit_image_get_data(fit, image_noffset, &data, &size)) { 149 printf("Can't get image data/size\n"); 150 return -1; 151 } 152 153 image_name = fit_get_name(fit, image_noffset, NULL); 154 155 /* Process all hash subnodes of the component image node */ 156 for (noffset = fdt_first_subnode(fit, image_noffset); 157 noffset >= 0; 158 noffset = fdt_next_subnode(fit, noffset)) { 159 const char *node_name; 160 int ret = 0; 161 162 /* 163 * Check subnode name, must be equal to "hash" or "signature". 164 * Multiple hash nodes require unique unit node 165 * names, e.g. hash@1, hash@2, signature@1, etc. 166 */ 167 node_name = fit_get_name(fit, noffset, NULL); 168 if (!strncmp(node_name, FIT_HASH_NODENAME, 169 strlen(FIT_HASH_NODENAME))) { 170 ret = fit_image_process_hash(fit, image_name, noffset, 171 data, size); 172 } 173 if (ret) 174 return -1; 175 } 176 177 return 0; 178 } 179 180 int fit_add_verification_data(void *fit) 181 { 182 int images_noffset; 183 int noffset; 184 int ret; 185 186 /* Find images parent node offset */ 187 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 188 if (images_noffset < 0) { 189 printf("Can't find images parent node '%s' (%s)\n", 190 FIT_IMAGES_PATH, fdt_strerror(images_noffset)); 191 return images_noffset; 192 } 193 194 /* Process its subnodes, print out component images details */ 195 for (noffset = fdt_first_subnode(fit, images_noffset); 196 noffset >= 0; 197 noffset = fdt_next_subnode(fit, noffset)) { 198 /* 199 * Direct child node of the images parent node, 200 * i.e. component image node. 201 */ 202 ret = fit_image_add_verification_data(fit, noffset); 203 if (ret) 204 return ret; 205 } 206 207 return 0; 208 } 209