diff --git a/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c index 91ee1bea9..c7f84afdf 100644 --- a/drivers/auth/auth_mod.c +++ b/drivers/auth/auth_mod.c @@ -222,19 +222,25 @@ static int auth_signature(const auth_method_param_sig_t *param, * To protect the system against rollback, the platform includes a non-volatile * counter whose value can only be increased. All certificates include a counter * value that should not be lower than the value stored in the platform. If the - * value is larger, the counter in the platform must be updated to the new - * value. + * value is larger, the counter in the platform must be updated to the new value + * (provided it has been authenticated). * * Return: 0 = success, Otherwise = error + * Returns additionally, + * cert_nv_ctr -> NV counter value present in the certificate + * need_nv_ctr_upgrade = 0 -> platform NV counter upgrade is not needed + * need_nv_ctr_upgrade = 1 -> platform NV counter upgrade is needed */ static int auth_nvctr(const auth_method_param_nv_ctr_t *param, const auth_img_desc_t *img_desc, - void *img, unsigned int img_len) + void *img, unsigned int img_len, + unsigned int *cert_nv_ctr, + bool *need_nv_ctr_upgrade) { char *p; void *data_ptr = NULL; unsigned int data_len, len, i; - unsigned int cert_nv_ctr, plat_nv_ctr; + unsigned int plat_nv_ctr; int rc = 0; /* Get the counter value from current image. The AM expects the IPM @@ -265,22 +271,20 @@ static int auth_nvctr(const auth_method_param_nv_ctr_t *param, } /* Convert to unsigned int. This code is for a little-endian CPU */ - cert_nv_ctr = 0; + *cert_nv_ctr = 0; for (i = 0; i < len; i++) { - cert_nv_ctr = (cert_nv_ctr << 8) | *p++; + *cert_nv_ctr = (*cert_nv_ctr << 8) | *p++; } /* Get the counter from the platform */ rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr); return_if_error(rc); - if (cert_nv_ctr < plat_nv_ctr) { + if (*cert_nv_ctr < plat_nv_ctr) { /* Invalid NV-counter */ return 1; - } else if (cert_nv_ctr > plat_nv_ctr) { - rc = plat_set_nv_ctr2(param->plat_nv_ctr->cookie, - img_desc, cert_nv_ctr); - return_if_error(rc); + } else if (*cert_nv_ctr > plat_nv_ctr) { + *need_nv_ctr_upgrade = true; } return 0; @@ -351,6 +355,10 @@ int auth_mod_verify_img(unsigned int img_id, void *param_ptr; unsigned int param_len; int rc, i; + unsigned int cert_nv_ctr = 0; + bool need_nv_ctr_upgrade = false; + bool sig_auth_done = false; + const auth_method_param_nv_ctr_t *nv_ctr_param = NULL; /* Get the image descriptor from the chain of trust */ img_desc = FCONF_GET_PROPERTY(tbbr, cot, img_id); @@ -376,10 +384,13 @@ int auth_mod_verify_img(unsigned int img_id, case AUTH_METHOD_SIG: rc = auth_signature(&auth_method->param.sig, img_desc, img_ptr, img_len); + sig_auth_done = true; break; case AUTH_METHOD_NV_CTR: - rc = auth_nvctr(&auth_method->param.nv_ctr, - img_desc, img_ptr, img_len); + nv_ctr_param = &auth_method->param.nv_ctr; + rc = auth_nvctr(nv_ctr_param, + img_desc, img_ptr, img_len, + &cert_nv_ctr, &need_nv_ctr_upgrade); break; default: /* Unknown authentication method */ @@ -389,6 +400,16 @@ int auth_mod_verify_img(unsigned int img_id, return_if_error(rc); } + /* + * Do platform NV counter upgrade only if the certificate gets + * authenticated, and platform NV-counter upgrade is needed. + */ + if (need_nv_ctr_upgrade && sig_auth_done) { + rc = plat_set_nv_ctr2(nv_ctr_param->plat_nv_ctr->cookie, + img_desc, cert_nv_ctr); + return_if_error(rc); + } + /* Extract the parameters indicated in the image descriptor to * authenticate the children images. */ if (img_desc->authenticated_data != NULL) {