Home | History | Annotate | Download | only in auth
      1 /*
      2  * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <assert.h>
      8 #include <auth_common.h>
      9 #include <auth_mod.h>
     10 #include <cot_def.h>
     11 #include <crypto_mod.h>
     12 #include <debug.h>
     13 #include <img_parser_mod.h>
     14 #include <platform.h>
     15 #include <platform_def.h>
     16 #include <stdint.h>
     17 #include <string.h>
     18 
     19 /* ASN.1 tags */
     20 #define ASN1_INTEGER                 0x02
     21 
     22 #define return_if_error(rc) \
     23 	do { \
     24 		if (rc != 0) { \
     25 			return rc; \
     26 		} \
     27 	} while (0)
     28 
     29 #pragma weak plat_set_nv_ctr2
     30 
     31 /* Pointer to CoT */
     32 extern const auth_img_desc_t *const cot_desc_ptr;
     33 extern unsigned int auth_img_flags[];
     34 
     35 static int cmp_auth_param_type_desc(const auth_param_type_desc_t *a,
     36 		const auth_param_type_desc_t *b)
     37 {
     38 	if ((a->type == b->type) && (a->cookie == b->cookie)) {
     39 		return 0;
     40 	}
     41 	return 1;
     42 }
     43 
     44 /*
     45  * This function obtains the requested authentication parameter data from the
     46  * information extracted from the parent image after its authentication.
     47  */
     48 static int auth_get_param(const auth_param_type_desc_t *param_type_desc,
     49 			  const auth_img_desc_t *img_desc,
     50 			  void **param, unsigned int *len)
     51 {
     52 	int i;
     53 
     54 	for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) {
     55 		if (0 == cmp_auth_param_type_desc(param_type_desc,
     56 				img_desc->authenticated_data[i].type_desc)) {
     57 			*param = img_desc->authenticated_data[i].data.ptr;
     58 			*len = img_desc->authenticated_data[i].data.len;
     59 			return 0;
     60 		}
     61 	}
     62 
     63 	return 1;
     64 }
     65 
     66 /*
     67  * Authenticate an image by matching the data hash
     68  *
     69  * This function implements 'AUTH_METHOD_HASH'. To authenticate an image using
     70  * this method, the image must contain:
     71  *
     72  *   - The data to calculate the hash from
     73  *
     74  * The parent image must contain:
     75  *
     76  *   - The hash to be matched with (including hash algorithm)
     77  *
     78  * For a successful authentication, both hashes must match. The function calls
     79  * the crypto-module to check this matching.
     80  *
     81  * Parameters:
     82  *   param: parameters to perform the hash authentication
     83  *   img_desc: pointer to image descriptor so we can know the image type
     84  *             and parent image
     85  *   img: pointer to image in memory
     86  *   img_len: length of image (in bytes)
     87  *
     88  * Return:
     89  *   0 = success, Otherwise = error
     90  */
     91 static int auth_hash(const auth_method_param_hash_t *param,
     92 		     const auth_img_desc_t *img_desc,
     93 		     void *img, unsigned int img_len)
     94 {
     95 	void *data_ptr, *hash_der_ptr;
     96 	unsigned int data_len, hash_der_len;
     97 	int rc = 0;
     98 
     99 	/* Get the hash from the parent image. This hash will be DER encoded
    100 	 * and contain the hash algorithm */
    101 	rc = auth_get_param(param->hash, img_desc->parent,
    102 			&hash_der_ptr, &hash_der_len);
    103 	return_if_error(rc);
    104 
    105 	/* Get the data to be hashed from the current image */
    106 	rc = img_parser_get_auth_param(img_desc->img_type, param->data,
    107 			img, img_len, &data_ptr, &data_len);
    108 	return_if_error(rc);
    109 
    110 	/* Ask the crypto module to verify this hash */
    111 	rc = crypto_mod_verify_hash(data_ptr, data_len,
    112 				    hash_der_ptr, hash_der_len);
    113 
    114 	return rc;
    115 }
    116 
    117 /*
    118  * Authenticate by digital signature
    119  *
    120  * This function implements 'AUTH_METHOD_SIG'. To authenticate an image using
    121  * this method, the image must contain:
    122  *
    123  *   - Data to be signed
    124  *   - Signature
    125  *   - Signature algorithm
    126  *
    127  * We rely on the image parser module to extract this data from the image.
    128  * The parent image must contain:
    129  *
    130  *   - Public key (or a hash of it)
    131  *
    132  * If the parent image contains only a hash of the key, we will try to obtain
    133  * the public key from the image itself (i.e. self-signed certificates). In that
    134  * case, the signature verification is considered just an integrity check and
    135  * the authentication is established by calculating the hash of the key and
    136  * comparing it with the hash obtained from the parent.
    137  *
    138  * If the image has no parent (NULL), it means it has to be authenticated using
    139  * the ROTPK stored in the platform. Again, this ROTPK could be the key itself
    140  * or a hash of it.
    141  *
    142  * Return: 0 = success, Otherwise = error
    143  */
    144 static int auth_signature(const auth_method_param_sig_t *param,
    145 			  const auth_img_desc_t *img_desc,
    146 			  void *img, unsigned int img_len)
    147 {
    148 	void *data_ptr, *pk_ptr, *pk_hash_ptr, *sig_ptr, *sig_alg_ptr;
    149 	unsigned int data_len, pk_len, pk_hash_len, sig_len, sig_alg_len;
    150 	unsigned int flags = 0;
    151 	int rc = 0;
    152 
    153 	/* Get the data to be signed from current image */
    154 	rc = img_parser_get_auth_param(img_desc->img_type, param->data,
    155 			img, img_len, &data_ptr, &data_len);
    156 	return_if_error(rc);
    157 
    158 	/* Get the signature from current image */
    159 	rc = img_parser_get_auth_param(img_desc->img_type, param->sig,
    160 			img, img_len, &sig_ptr, &sig_len);
    161 	return_if_error(rc);
    162 
    163 	/* Get the signature algorithm from current image */
    164 	rc = img_parser_get_auth_param(img_desc->img_type, param->alg,
    165 			img, img_len, &sig_alg_ptr, &sig_alg_len);
    166 	return_if_error(rc);
    167 
    168 	/* Get the public key from the parent. If there is no parent (NULL),
    169 	 * the certificate has been signed with the ROTPK, so we have to get
    170 	 * the PK from the platform */
    171 	if (img_desc->parent) {
    172 		rc = auth_get_param(param->pk, img_desc->parent,
    173 				&pk_ptr, &pk_len);
    174 	} else {
    175 		rc = plat_get_rotpk_info(param->pk->cookie, &pk_ptr, &pk_len,
    176 				&flags);
    177 	}
    178 	return_if_error(rc);
    179 
    180 	if (flags & (ROTPK_IS_HASH | ROTPK_NOT_DEPLOYED)) {
    181 		/* If the PK is a hash of the key or if the ROTPK is not
    182 		   deployed on the platform, retrieve the key from the image */
    183 		pk_hash_ptr = pk_ptr;
    184 		pk_hash_len = pk_len;
    185 		rc = img_parser_get_auth_param(img_desc->img_type,
    186 					param->pk, img, img_len,
    187 					&pk_ptr, &pk_len);
    188 		return_if_error(rc);
    189 
    190 		/* Ask the crypto module to verify the signature */
    191 		rc = crypto_mod_verify_signature(data_ptr, data_len,
    192 						 sig_ptr, sig_len,
    193 						 sig_alg_ptr, sig_alg_len,
    194 						 pk_ptr, pk_len);
    195 		return_if_error(rc);
    196 
    197 		if (flags & ROTPK_NOT_DEPLOYED) {
    198 			NOTICE("ROTPK is not deployed on platform. "
    199 				"Skipping ROTPK verification.\n");
    200 		} else {
    201 			/* Ask the crypto-module to verify the key hash */
    202 			rc = crypto_mod_verify_hash(pk_ptr, pk_len,
    203 				    pk_hash_ptr, pk_hash_len);
    204 		}
    205 	} else {
    206 		/* Ask the crypto module to verify the signature */
    207 		rc = crypto_mod_verify_signature(data_ptr, data_len,
    208 						 sig_ptr, sig_len,
    209 						 sig_alg_ptr, sig_alg_len,
    210 						 pk_ptr, pk_len);
    211 	}
    212 
    213 	return rc;
    214 }
    215 
    216 /*
    217  * Authenticate by Non-Volatile counter
    218  *
    219  * To protect the system against rollback, the platform includes a non-volatile
    220  * counter whose value can only be increased. All certificates include a counter
    221  * value that should not be lower than the value stored in the platform. If the
    222  * value is larger, the counter in the platform must be updated to the new
    223  * value.
    224  *
    225  * Return: 0 = success, Otherwise = error
    226  */
    227 static int auth_nvctr(const auth_method_param_nv_ctr_t *param,
    228 		      const auth_img_desc_t *img_desc,
    229 		      void *img, unsigned int img_len)
    230 {
    231 	char *p;
    232 	void *data_ptr = NULL;
    233 	unsigned int data_len, len, i;
    234 	unsigned int cert_nv_ctr, plat_nv_ctr;
    235 	int rc = 0;
    236 
    237 	/* Get the counter value from current image. The AM expects the IPM
    238 	 * to return the counter value as a DER encoded integer */
    239 	rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr,
    240 				       img, img_len, &data_ptr, &data_len);
    241 	return_if_error(rc);
    242 
    243 	/* Parse the DER encoded integer */
    244 	assert(data_ptr);
    245 	p = (char *)data_ptr;
    246 	if (*p != ASN1_INTEGER) {
    247 		/* Invalid ASN.1 integer */
    248 		return 1;
    249 	}
    250 	p++;
    251 
    252 	/* NV-counters are unsigned integers up to 32-bit */
    253 	len = (unsigned int)(*p & 0x7f);
    254 	if ((*p & 0x80) || (len > 4)) {
    255 		return 1;
    256 	}
    257 	p++;
    258 
    259 	/* Check the number is not negative */
    260 	if (*p & 0x80) {
    261 		return 1;
    262 	}
    263 
    264 	/* Convert to unsigned int. This code is for a little-endian CPU */
    265 	cert_nv_ctr = 0;
    266 	for (i = 0; i < len; i++) {
    267 		cert_nv_ctr = (cert_nv_ctr << 8) | *p++;
    268 	}
    269 
    270 	/* Get the counter from the platform */
    271 	rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr);
    272 	return_if_error(rc);
    273 
    274 	if (cert_nv_ctr < plat_nv_ctr) {
    275 		/* Invalid NV-counter */
    276 		return 1;
    277 	} else if (cert_nv_ctr > plat_nv_ctr) {
    278 		rc = plat_set_nv_ctr2(param->plat_nv_ctr->cookie,
    279 			img_desc, cert_nv_ctr);
    280 		return_if_error(rc);
    281 	}
    282 
    283 	return 0;
    284 }
    285 
    286 int plat_set_nv_ctr2(void *cookie, const auth_img_desc_t *img_desc __unused,
    287 		unsigned int nv_ctr)
    288 {
    289 	return plat_set_nv_ctr(cookie, nv_ctr);
    290 }
    291 
    292 /*
    293  * Return the parent id in the output parameter '*parent_id'
    294  *
    295  * Return value:
    296  *   0 = Image has parent, 1 = Image has no parent or parent is authenticated
    297  */
    298 int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id)
    299 {
    300 	const auth_img_desc_t *img_desc = NULL;
    301 
    302 	assert(parent_id != NULL);
    303 
    304 	/* Get the image descriptor */
    305 	img_desc = &cot_desc_ptr[img_id];
    306 
    307 	/* Check if the image has no parent (ROT) */
    308 	if (img_desc->parent == NULL) {
    309 		*parent_id = 0;
    310 		return 1;
    311 	}
    312 
    313 	/* Check if the parent has already been authenticated */
    314 	if (auth_img_flags[img_desc->parent->img_id] & IMG_FLAG_AUTHENTICATED) {
    315 		*parent_id = 0;
    316 		return 1;
    317 	}
    318 
    319 	*parent_id = img_desc->parent->img_id;
    320 	return 0;
    321 }
    322 
    323 /*
    324  * Initialize the different modules in the authentication framework
    325  */
    326 void auth_mod_init(void)
    327 {
    328 	/* Check we have a valid CoT registered */
    329 	assert(cot_desc_ptr != NULL);
    330 
    331 	/* Crypto module */
    332 	crypto_mod_init();
    333 
    334 	/* Image parser module */
    335 	img_parser_init();
    336 }
    337 
    338 /*
    339  * Authenticate a certificate/image
    340  *
    341  * Return: 0 = success, Otherwise = error
    342  */
    343 int auth_mod_verify_img(unsigned int img_id,
    344 			void *img_ptr,
    345 			unsigned int img_len)
    346 {
    347 	const auth_img_desc_t *img_desc = NULL;
    348 	const auth_method_desc_t *auth_method = NULL;
    349 	void *param_ptr;
    350 	unsigned int param_len;
    351 	int rc, i;
    352 
    353 	/* Get the image descriptor from the chain of trust */
    354 	img_desc = &cot_desc_ptr[img_id];
    355 
    356 	/* Ask the parser to check the image integrity */
    357 	rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len);
    358 	return_if_error(rc);
    359 
    360 	/* Authenticate the image using the methods indicated in the image
    361 	 * descriptor. */
    362 	for (i = 0 ; i < AUTH_METHOD_NUM ; i++) {
    363 		auth_method = &img_desc->img_auth_methods[i];
    364 		switch (auth_method->type) {
    365 		case AUTH_METHOD_NONE:
    366 			rc = 0;
    367 			break;
    368 		case AUTH_METHOD_HASH:
    369 			rc = auth_hash(&auth_method->param.hash,
    370 					img_desc, img_ptr, img_len);
    371 			break;
    372 		case AUTH_METHOD_SIG:
    373 			rc = auth_signature(&auth_method->param.sig,
    374 					img_desc, img_ptr, img_len);
    375 			break;
    376 		case AUTH_METHOD_NV_CTR:
    377 			rc = auth_nvctr(&auth_method->param.nv_ctr,
    378 					img_desc, img_ptr, img_len);
    379 			break;
    380 		default:
    381 			/* Unknown authentication method */
    382 			rc = 1;
    383 			break;
    384 		}
    385 		return_if_error(rc);
    386 	}
    387 
    388 	/* Extract the parameters indicated in the image descriptor to
    389 	 * authenticate the children images. */
    390 	for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) {
    391 		if (img_desc->authenticated_data[i].type_desc == NULL) {
    392 			continue;
    393 		}
    394 
    395 		/* Get the parameter from the image parser module */
    396 		rc = img_parser_get_auth_param(img_desc->img_type,
    397 				img_desc->authenticated_data[i].type_desc,
    398 				img_ptr, img_len, &param_ptr, &param_len);
    399 		return_if_error(rc);
    400 
    401 		/* Check parameter size */
    402 		if (param_len > img_desc->authenticated_data[i].data.len) {
    403 			return 1;
    404 		}
    405 
    406 		/* Copy the parameter for later use */
    407 		memcpy((void *)img_desc->authenticated_data[i].data.ptr,
    408 				(void *)param_ptr, param_len);
    409 	}
    410 
    411 	/* Mark image as authenticated */
    412 	auth_img_flags[img_desc->img_id] |= IMG_FLAG_AUTHENTICATED;
    413 
    414 	return 0;
    415 }
    416