diff mbox series

[RFC,1/1] image: add anti rollback protection for FIT Images

Message ID 7bb443952704d347bea760554410b432a3b339b6.1598373235.git.thiruan@linux.microsoft.com
State RFC
Delegated to: Tom Rini
Headers show
Series Anti rollback protection for FIT Images | expand

Commit Message

Thirupathaiah Annapureddy Sept. 1, 2020, 8:48 p.m. UTC
Anti rollback protection is required when there is a need to retire
previous versions of FIT images due to security flaws in them.
Currently U-Boot Verified boot does not have rollback protection to
protect against known security flaws.

This change adds anti-rollback protection for FIT images.

Signed-off-by: Thirupathaiah Annapureddy <thiruan@linux.microsoft.com>
---
 Kconfig                |  9 +++++
 common/image-fit-sig.c | 79 ++++++++++++++++++++++++++++++++++++++++++
 common/image-fit.c     | 24 +++++++++++++
 include/image.h        | 23 ++++++++++++
 4 files changed, 135 insertions(+)

Comments

Simon Glass Sept. 7, 2020, 1:43 a.m. UTC | #1
Hi Thirupathaiah,

On Tue, 1 Sep 2020 at 14:48, Thirupathaiah Annapureddy
<thiruan@linux.microsoft.com> wrote:
>
> Anti rollback protection is required when there is a need to retire
> previous versions of FIT images due to security flaws in them.
> Currently U-Boot Verified boot does not have rollback protection to
> protect against known security flaws.
>
> This change adds anti-rollback protection for FIT images.
>
> Signed-off-by: Thirupathaiah Annapureddy <thiruan@linux.microsoft.com>
> ---
>  Kconfig                |  9 +++++
>  common/image-fit-sig.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>  common/image-fit.c     | 24 +++++++++++++
>  include/image.h        | 23 ++++++++++++
>  4 files changed, 135 insertions(+)

Good to see this. I have a few comments though. This needs to be done
very carefully as it affects security.

>
> diff --git a/Kconfig b/Kconfig
> index 883e3f71d0..3959a6592c 100644
> --- a/Kconfig
> +++ b/Kconfig
> @@ -533,6 +533,15 @@ config FIT_CIPHER
>           Enable the feature of data ciphering/unciphering in the tool mkimage
>           and in the u-boot support of the FIT image.
>
> +config FIT_ARBP

How about using ROLLBACK instead of ARBP. It is easier to understand.

> +       bool "Enable Anti rollback version check for FIT images"

anti-rollback (add hyphen)

> +       depends on FIT_SIGNATURE
> +       default n
> +       help
> +         Enable this to activate anti-rollback protection. This is required
> +         when a platform needs to retire previous versions of FIT images due to
> +         security flaws in in them.

in

> +
>  config FIT_VERBOSE
>         bool "Show verbose messages when FIT images fail"
>         help
> diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c
> index cc1967109e..5103508894 100644
> --- a/common/image-fit-sig.c
> +++ b/common/image-fit-sig.c
> @@ -78,6 +78,35 @@ struct image_region *fit_region_make_list(const void *fit,
>         return region;
>  }
>
> +#if !defined(USE_HOSTCC)
> +static int fit_image_verify_arbvn(const void *fit, int image_noffset)

Please add a comment as to what this does and what it checks

> +{
> +       uint8_t type;
> +       uint32_t image_arbvn;
> +       uint32_t plat_arbvn = 0;

Those three can be uint.

> +       int ret;
> +
> +       ret = fit_image_get_arbvn(fit, image_noffset, &image_arbvn);
> +       if (ret)
> +               return 0;
> +
> +       ret = fit_image_get_type(fit, image_noffset, &type);
> +       if (ret)
> +               return 0;
> +
> +       ret = board_get_arbvn(type, &plat_arbvn);
> +
> +       if (image_arbvn < plat_arbvn) {
> +               return -EPERM;
> +       } else if (image_arbvn > plat_arbvn) {
> +               ret = board_set_arbvn(type, image_arbvn);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
>  static int fit_image_setup_verify(struct image_sign_info *info,
>                                   const void *fit, int noffset,
>                                   int required_keynode, char **err_msgp)
> @@ -181,6 +210,14 @@ static int fit_image_verify_sig(const void *fit, int image_noffset,
>                 goto error;
>         }
>
> +#if !defined(USE_HOSTCC)
> +       if (IMAGE_ENABLE_ARBP && verified) {
> +               ret = fit_image_verify_arbvn(fit, image_noffset);
> +               if (ret)
> +                       verified = 0;
> +       }
> +#endif
> +
>         return verified ? 0 : -EPERM;
>
>  error:
> @@ -370,6 +407,40 @@ static int fit_config_check_sig(const void *fit, int noffset,
>         return 0;
>  }
>
> +#if !defined(USE_HOSTCC)
> +static int fit_config_verify_arbvn(const void *fit, int conf_noffset,
> +                                  int sig_offset)
> +{
> +       static const char default_list[] = FIT_KERNEL_PROP "\0"
> +                       FIT_FDT_PROP;
> +       int ret, len;
> +       const char *prop, *iname, *end;
> +       int image_noffset;
> +
> +       /* If there is "sign-images" property, use that */
> +       prop = fdt_getprop(fit, sig_offset, "sign-images", &len);
> +       if (!prop) {
> +               prop = default_list;
> +               len = sizeof(default_list);
> +       }
> +
> +       /* Locate the images */
> +       end = prop + len;
> +       for (iname = prop; iname < end; iname += strlen(iname) + 1) {
> +               image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
> +                                                      iname);
> +               if (image_noffset < 0)
> +                       return -ENOENT;
> +
> +               ret = fit_image_verify_arbvn(fit, image_noffset);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
>  static int fit_config_verify_sig(const void *fit, int conf_noffset,
>                                  const void *sig_blob, int sig_offset)
>  {
> @@ -401,6 +472,14 @@ static int fit_config_verify_sig(const void *fit, int conf_noffset,
>                 goto error;
>         }
>
> +#if !defined(USE_HOSTCC)

Do we need this £ifdef, or can we rely on IMAGE_ENABLE_ARBP?

> +       if (IMAGE_ENABLE_ARBP && verified) {
> +               ret = fit_config_verify_arbvn(fit, conf_noffset, noffset);
> +               if (ret)
> +                       verified = 0;
> +       }
> +#endif
> +
>         if (verified)
>                 return 0;
>
> diff --git a/common/image-fit.c b/common/image-fit.c
> index d54eff9033..97029853b9 100644
> --- a/common/image-fit.c
> +++ b/common/image-fit.c
> @@ -1025,6 +1025,30 @@ int fit_image_get_data_and_size(const void *fit, int noffset,
>         return ret;
>  }
>
> +/**
> + * Get 'arbvn' property from a given image node.
> + *
> + * @fit: pointer to the FIT image header
> + * @noffset: component image node offset
> + * @arbvn: holds the arbvn property value
> + *
> + * returns:
> + *     0, on success
> + *     -ENOENT if the property could not be found
> + */
> +int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn)

fit_image_get_rollback()

s/arbvn/versionp/

> +{
> +       const fdt32_t *val;
> +
> +       val = fdt_getprop(fit, noffset, FIT_ARBVN_PROP, NULL);
> +       if (!val)
> +               return -ENOENT;
> +
> +       *arbvn = fdt32_to_cpu(*val);
> +
> +       return 0;
> +}
> +
>  /**
>   * fit_image_hash_get_algo - get hash algorithm name
>   * @fit: pointer to the FIT format image header
> diff --git a/include/image.h b/include/image.h
> index 9a5a87dbf8..72a963cf27 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -1005,6 +1005,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
>  #define FIT_COMP_PROP          "compression"
>  #define FIT_ENTRY_PROP         "entry"
>  #define FIT_LOAD_PROP          "load"
> +#define FIT_ARBVN_PROP         "arbvn"

ROLLBACK / "rollback"

>
>  /* configuration node */
>  #define FIT_KERNEL_PROP                "kernel"
> @@ -1085,6 +1086,7 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset,
>                                        size_t *data_size);
>  int fit_image_get_data_and_size(const void *fit, int noffset,
>                                 const void **data, size_t *size);
> +int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn);

Please add a full function comment

>
>  int fit_image_hash_get_algo(const void *fit, int noffset, char **algo);
>  int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
> @@ -1186,6 +1188,7 @@ int calculate_hash(const void *data, int data_len, const char *algo,
>   * device
>   */
>  #if defined(USE_HOSTCC)
> +# define IMAGE_ENABLE_ARBP     0
>  # if defined(CONFIG_FIT_SIGNATURE)
>  #  define IMAGE_ENABLE_SIGN    1
>  #  define IMAGE_ENABLE_VERIFY  1
> @@ -1200,6 +1203,7 @@ int calculate_hash(const void *data, int data_len, const char *algo,
>  # define IMAGE_ENABLE_SIGN     0
>  # define IMAGE_ENABLE_VERIFY           CONFIG_IS_ENABLED(RSA_VERIFY)
>  # define FIT_IMAGE_ENABLE_VERIFY       CONFIG_IS_ENABLED(FIT_SIGNATURE)
> +# define IMAGE_ENABLE_ARBP             CONFIG_IS_ENABLED(FIT_ARBP)
>  #endif
>
>  #if IMAGE_ENABLE_FIT
> @@ -1544,6 +1548,25 @@ int board_fit_config_name_match(const char *name);
>  void board_fit_image_post_process(void **p_image, size_t *p_size);
>  #endif /* CONFIG_SPL_FIT_IMAGE_POST_PROCESS */
>
> +#if defined(CONFIG_FIT_ARBP)
> +/**
> + * board_get_arbvn() - get the arbvn stored in the platform secure storage.
> + *
> + * @ih_type: image type
> + * @arbvn: pointer to the arbvn
> + * @return 0 if upon successful retrieval, non-zero upon failure.
> + */
> +int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);

This needs a driver since the rollback counter may be implemented by a
TPM or anything. If you want to use the board, add a new
get_rollback() to UCLASS_BOARD (board.h). Or you could create a new
UCLASS_SECURITY which includes these two API calls.

> +/**
> + * board_set_arbvn() - set the arbvn stored in the platform secure storage.
> + *
> + * @ih_type: image type
> + * @arbvn: new arbvn value to store in the platform secure storage.
> + * @return 0 if stored successfully, non-zero upon failure.
> + */
> +int board_set_arbvn(uint8_t ih_type, uint32_t arbvn);
> +#endif /* CONFIG_FIT_ARBP */
> +
>  #define FDT_ERROR      ((ulong)(-1))
>
>  ulong fdt_getprop_u32(const void *fdt, int node, const char *prop);
> --
> 2.25.2
>

Also please update the vboot test to add a check for rollback.

Regards,
Simon
Thirupathaiah Annapureddy Sept. 15, 2020, 6:18 a.m. UTC | #2
Hi Simon,

Thanks for the review.

On 9/6/2020 6:43 PM, Simon Glass wrote:
>>
>> diff --git a/Kconfig b/Kconfig
>> index 883e3f71d0..3959a6592c 100644
>> --- a/Kconfig
>> +++ b/Kconfig
>> @@ -533,6 +533,15 @@ config FIT_CIPHER
>>           Enable the feature of data ciphering/unciphering in the tool mkimage
>>           and in the u-boot support of the FIT image.
>>
>> +config FIT_ARBP
> 
> How about using ROLLBACK instead of ARBP. It is easier to understand.Looks good to me. I will change it in the next version of the patch.

>> +{
>> +       uint8_t type;
>> +       uint32_t image_arbvn;
>> +       uint32_t plat_arbvn = 0;
> 
> Those three can be uint.
fit_image_get_type() returns type as uint8_t. 
I can change it for the other two variables. 

>>  static int fit_config_verify_sig(const void *fit, int conf_noffset,
>>                                  const void *sig_blob, int sig_offset)
>>  {
>> @@ -401,6 +472,14 @@ static int fit_config_verify_sig(const void *fit, int conf_noffset,
>>                 goto error;
>>         }
>>
>> +#if !defined(USE_HOSTCC)
> 
> Do we need this £ifdef, or can we rely on IMAGE_ENABLE_ARBP?
I believe we can rely on just IMAGE_ENABLE_ARBP.

>>  #define FIT_LOAD_PROP          "load"
>> +#define FIT_ARBVN_PROP         "arbvn"
> 
> ROLLBACK / "rollback"
I will fix it in the next version.

> 
>>
>>  /* configuration node */
>>  #define FIT_KERNEL_PROP                "kernel"
>> @@ -1085,6 +1086,7 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset,
>>                                        size_t *data_size);
>>  int fit_image_get_data_and_size(const void *fit, int noffset,
>>                                 const void **data, size_t *size);
>> +int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn);
> 
> Please add a full function comment
comment was added before the function definition to be consistent
with other functions.

>> +int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);
> 
> This needs a driver since the rollback counter may be implemented by a
> TPM or anything. 
Board specific hooks can leverage TPM library functions in that case.
May I know why a driver is needed?

> If you want to use the board, add a new
> get_rollback() to UCLASS_BOARD (board.h). Or you could create a new
> UCLASS_SECURITY which includes these two API calls.
I explored the option of using UCLASS_BOARD. But it does not have "set"
interfaces and the "id" parameter used in "get" functions seem to be
board specific. We can look into the option of UCLASS_SECURITY for these
two API calls.

> 
> Also please update the vboot test to add a check for rollback.

Yes, will do in the next version of the patch series.

Best Regards,
Thiru
Tom Rini Sept. 15, 2020, 1:40 p.m. UTC | #3
On Mon, Sep 14, 2020 at 11:18:25PM -0700, Thirupathaiah Annapureddy wrote:
> Hi Simon,
> 
> Thanks for the review.
> 
> On 9/6/2020 6:43 PM, Simon Glass wrote:
> >>
> >> diff --git a/Kconfig b/Kconfig
> >> index 883e3f71d0..3959a6592c 100644
> >> --- a/Kconfig
> >> +++ b/Kconfig
> >> @@ -533,6 +533,15 @@ config FIT_CIPHER
> >>           Enable the feature of data ciphering/unciphering in the tool mkimage
> >>           and in the u-boot support of the FIT image.
> >>
> >> +config FIT_ARBP
> > 
> > How about using ROLLBACK instead of ARBP. It is easier to understand.Looks good to me. I will change it in the next version of the patch.
> 
> >> +{
> >> +       uint8_t type;
> >> +       uint32_t image_arbvn;
> >> +       uint32_t plat_arbvn = 0;
> > 
> > Those three can be uint.
> fit_image_get_type() returns type as uint8_t. 
> I can change it for the other two variables. 
> 
> >>  static int fit_config_verify_sig(const void *fit, int conf_noffset,
> >>                                  const void *sig_blob, int sig_offset)
> >>  {
> >> @@ -401,6 +472,14 @@ static int fit_config_verify_sig(const void *fit, int conf_noffset,
> >>                 goto error;
> >>         }
> >>
> >> +#if !defined(USE_HOSTCC)
> > 
> > Do we need this £ifdef, or can we rely on IMAGE_ENABLE_ARBP?
> I believe we can rely on just IMAGE_ENABLE_ARBP.
> 
> >>  #define FIT_LOAD_PROP          "load"
> >> +#define FIT_ARBVN_PROP         "arbvn"
> > 
> > ROLLBACK / "rollback"
> I will fix it in the next version.
> 
> > 
> >>
> >>  /* configuration node */
> >>  #define FIT_KERNEL_PROP                "kernel"
> >> @@ -1085,6 +1086,7 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset,
> >>                                        size_t *data_size);
> >>  int fit_image_get_data_and_size(const void *fit, int noffset,
> >>                                 const void **data, size_t *size);
> >> +int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn);
> > 
> > Please add a full function comment
> comment was added before the function definition to be consistent
> with other functions.
> 
> >> +int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);
> > 
> > This needs a driver since the rollback counter may be implemented by a
> > TPM or anything. 
> Board specific hooks can leverage TPM library functions in that case.
> May I know why a driver is needed?

Sorry for not getting in to this series sooner.  One thing that I think
would be very helpful is to see is a full demonstration on say a
Raspberry Pi.  I know I have a TPM2 module that supports Pi sitting
around here.  I assume you've also tested this on some HW platform.
Thirupathaiah Annapureddy Sept. 15, 2020, 7:46 p.m. UTC | #4
Hi Tom,

Please see my comment(s) in-line.

On 9/15/2020 6:40 AM, Tom Rini wrote:
> On Mon, Sep 14, 2020 at 11:18:25PM -0700, Thirupathaiah Annapureddy wrote:
>> Hi Simon,
>>
>> Thanks for the review.
>>
>> On 9/6/2020 6:43 PM, Simon Glass wrote:
>>>>
>>>> diff --git a/Kconfig b/Kconfig
>>>> index 883e3f71d0..3959a6592c 100644
>>>> --- a/Kconfig
>>>> +++ b/Kconfig
>>>> @@ -533,6 +533,15 @@ config FIT_CIPHER
>>>>           Enable the feature of data ciphering/unciphering in the tool mkimage
>>>>           and in the u-boot support of the FIT image.
>>>>
>>>> +config FIT_ARBP
>>>
>>> How about using ROLLBACK instead of ARBP. It is easier to understand.Looks good to me. I will change it in the next version of the patch.
>>
>>>> +{
>>>> +       uint8_t type;
>>>> +       uint32_t image_arbvn;
>>>> +       uint32_t plat_arbvn = 0;
>>>
>>> Those three can be uint.
>> fit_image_get_type() returns type as uint8_t. 
>> I can change it for the other two variables. 
>>
>>>>  static int fit_config_verify_sig(const void *fit, int conf_noffset,
>>>>                                  const void *sig_blob, int sig_offset)
>>>>  {
>>>> @@ -401,6 +472,14 @@ static int fit_config_verify_sig(const void *fit, int conf_noffset,
>>>>                 goto error;
>>>>         }
>>>>
>>>> +#if !defined(USE_HOSTCC)
>>>
>>> Do we need this £ifdef, or can we rely on IMAGE_ENABLE_ARBP?
>> I believe we can rely on just IMAGE_ENABLE_ARBP.
>>
>>>>  #define FIT_LOAD_PROP          "load"
>>>> +#define FIT_ARBVN_PROP         "arbvn"
>>>
>>> ROLLBACK / "rollback"
>> I will fix it in the next version.
>>
>>>
>>>>
>>>>  /* configuration node */
>>>>  #define FIT_KERNEL_PROP                "kernel"
>>>> @@ -1085,6 +1086,7 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset,
>>>>                                        size_t *data_size);
>>>>  int fit_image_get_data_and_size(const void *fit, int noffset,
>>>>                                 const void **data, size_t *size);
>>>> +int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn);
>>>
>>> Please add a full function comment
>> comment was added before the function definition to be consistent
>> with other functions.
>>
>>>> +int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);
>>>
>>> This needs a driver since the rollback counter may be implemented by a
>>> TPM or anything. 
>> Board specific hooks can leverage TPM library functions in that case.
>> May I know why a driver is needed?
> 
> Sorry for not getting in to this series sooner.  One thing that I think
> would be very helpful is to see is a full demonstration on say a
> Raspberry Pi.  I know I have a TPM2 module that supports Pi sitting
> around here.  I assume you've also tested this on some HW platform.
> 

We test patches on our own hardware. But I agree demonstration of this
feature on more widely available hardware is useful. I will include
board (ex: Raspberry Pi) specific changes in the next version of the patch
series.

Best Regards,
Thiru
Simon Glass Sept. 15, 2020, 9:18 p.m. UTC | #5
Hi Thirupathaiah,

On Tue, 15 Sep 2020 at 00:18, Thirupathaiah Annapureddy
<thiruan@linux.microsoft.com> wrote:
>
> Hi Simon,
>
> Thanks for the review.
>
> On 9/6/2020 6:43 PM, Simon Glass wrote:
> >>
> >> diff --git a/Kconfig b/Kconfig
> >> index 883e3f71d0..3959a6592c 100644
> >> --- a/Kconfig
> >> +++ b/Kconfig
> >> @@ -533,6 +533,15 @@ config FIT_CIPHER
> >>           Enable the feature of data ciphering/unciphering in the tool mkimage
> >>           and in the u-boot support of the FIT image.
> >>
> >> +config FIT_ARBP
> >
> > How about using ROLLBACK instead of ARBP. It is easier to understand.Looks good to me. I will change it in the next version of the patch.
>
> >> +{
> >> +       uint8_t type;
> >> +       uint32_t image_arbvn;
> >> +       uint32_t plat_arbvn = 0;
> >
> > Those three can be uint.
> fit_image_get_type() returns type as uint8_t.
> I can change it for the other two variables.

My point here is just that you are declaring variables which end up
being in registers. It doesn't make sense to try to choose a small
type just because it will fit. The machine registers are 32/64-bits.
Using an 8-bit variable can only increase code size as the compiler
may have to mask things off before storing and passing values.

It is fine to use these sorts of types in a data structure to save
memory, or in a protocol to ensure the bits are correct, but it really
doesn't make sense for local variables and parameters.

[..]

> >> +int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);
> >
> > This needs a driver since the rollback counter may be implemented by a
> > TPM or anything.
> Board specific hooks can leverage TPM library functions in that case.
> May I know why a driver is needed?

U-Boot uses driver model to deal with the complexity of the system. It
allows the system to be described by devicetree, it allows different
drivers to be created to implement the same functionality. It is more
discoverable than weak functions and less error-prone.

>
> > If you want to use the board, add a new
> > get_rollback() to UCLASS_BOARD (board.h). Or you could create a new
> > UCLASS_SECURITY which includes these two API calls.
> I explored the option of using UCLASS_BOARD. But it does not have "set"
> interfaces and the "id" parameter used in "get" functions seem to be
> board specific. We can look into the option of UCLASS_SECURITY for these
> two API calls.

OK that sounds good.

[..]

Regards,
Simon
diff mbox series

Patch

diff --git a/Kconfig b/Kconfig
index 883e3f71d0..3959a6592c 100644
--- a/Kconfig
+++ b/Kconfig
@@ -533,6 +533,15 @@  config FIT_CIPHER
 	  Enable the feature of data ciphering/unciphering in the tool mkimage
 	  and in the u-boot support of the FIT image.
 
+config FIT_ARBP
+	bool "Enable Anti rollback version check for FIT images"
+	depends on FIT_SIGNATURE
+	default n
+	help
+	  Enable this to activate anti-rollback protection. This is required
+	  when a platform needs to retire previous versions of FIT images due to
+	  security flaws in in them.
+
 config FIT_VERBOSE
 	bool "Show verbose messages when FIT images fail"
 	help
diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c
index cc1967109e..5103508894 100644
--- a/common/image-fit-sig.c
+++ b/common/image-fit-sig.c
@@ -78,6 +78,35 @@  struct image_region *fit_region_make_list(const void *fit,
 	return region;
 }
 
+#if !defined(USE_HOSTCC)
+static int fit_image_verify_arbvn(const void *fit, int image_noffset)
+{
+	uint8_t type;
+	uint32_t image_arbvn;
+	uint32_t plat_arbvn = 0;
+	int ret;
+
+	ret = fit_image_get_arbvn(fit, image_noffset, &image_arbvn);
+	if (ret)
+		return 0;
+
+	ret = fit_image_get_type(fit, image_noffset, &type);
+	if (ret)
+		return 0;
+
+	ret = board_get_arbvn(type, &plat_arbvn);
+
+	if (image_arbvn < plat_arbvn) {
+		return -EPERM;
+	} else if (image_arbvn > plat_arbvn) {
+		ret = board_set_arbvn(type, image_arbvn);
+		return ret;
+	}
+
+	return 0;
+}
+#endif
+
 static int fit_image_setup_verify(struct image_sign_info *info,
 				  const void *fit, int noffset,
 				  int required_keynode, char **err_msgp)
@@ -181,6 +210,14 @@  static int fit_image_verify_sig(const void *fit, int image_noffset,
 		goto error;
 	}
 
+#if !defined(USE_HOSTCC)
+	if (IMAGE_ENABLE_ARBP && verified) {
+		ret = fit_image_verify_arbvn(fit, image_noffset);
+		if (ret)
+			verified = 0;
+	}
+#endif
+
 	return verified ? 0 : -EPERM;
 
 error:
@@ -370,6 +407,40 @@  static int fit_config_check_sig(const void *fit, int noffset,
 	return 0;
 }
 
+#if !defined(USE_HOSTCC)
+static int fit_config_verify_arbvn(const void *fit, int conf_noffset,
+				   int sig_offset)
+{
+	static const char default_list[] = FIT_KERNEL_PROP "\0"
+			FIT_FDT_PROP;
+	int ret, len;
+	const char *prop, *iname, *end;
+	int image_noffset;
+
+	/* If there is "sign-images" property, use that */
+	prop = fdt_getprop(fit, sig_offset, "sign-images", &len);
+	if (!prop) {
+		prop = default_list;
+		len = sizeof(default_list);
+	}
+
+	/* Locate the images */
+	end = prop + len;
+	for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+		image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+						       iname);
+		if (image_noffset < 0)
+			return -ENOENT;
+
+		ret = fit_image_verify_arbvn(fit, image_noffset);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
 static int fit_config_verify_sig(const void *fit, int conf_noffset,
 				 const void *sig_blob, int sig_offset)
 {
@@ -401,6 +472,14 @@  static int fit_config_verify_sig(const void *fit, int conf_noffset,
 		goto error;
 	}
 
+#if !defined(USE_HOSTCC)
+	if (IMAGE_ENABLE_ARBP && verified) {
+		ret = fit_config_verify_arbvn(fit, conf_noffset, noffset);
+		if (ret)
+			verified = 0;
+	}
+#endif
+
 	if (verified)
 		return 0;
 
diff --git a/common/image-fit.c b/common/image-fit.c
index d54eff9033..97029853b9 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -1025,6 +1025,30 @@  int fit_image_get_data_and_size(const void *fit, int noffset,
 	return ret;
 }
 
+/**
+ * Get 'arbvn' property from a given image node.
+ *
+ * @fit: pointer to the FIT image header
+ * @noffset: component image node offset
+ * @arbvn: holds the arbvn property value
+ *
+ * returns:
+ *     0, on success
+ *     -ENOENT if the property could not be found
+ */
+int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn)
+{
+	const fdt32_t *val;
+
+	val = fdt_getprop(fit, noffset, FIT_ARBVN_PROP, NULL);
+	if (!val)
+		return -ENOENT;
+
+	*arbvn = fdt32_to_cpu(*val);
+
+	return 0;
+}
+
 /**
  * fit_image_hash_get_algo - get hash algorithm name
  * @fit: pointer to the FIT format image header
diff --git a/include/image.h b/include/image.h
index 9a5a87dbf8..72a963cf27 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1005,6 +1005,7 @@  int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
 #define FIT_COMP_PROP		"compression"
 #define FIT_ENTRY_PROP		"entry"
 #define FIT_LOAD_PROP		"load"
+#define FIT_ARBVN_PROP		"arbvn"
 
 /* configuration node */
 #define FIT_KERNEL_PROP		"kernel"
@@ -1085,6 +1086,7 @@  int fit_image_get_data_size_unciphered(const void *fit, int noffset,
 				       size_t *data_size);
 int fit_image_get_data_and_size(const void *fit, int noffset,
 				const void **data, size_t *size);
+int fit_image_get_arbvn(const void *fit, int noffset, uint32_t *arbvn);
 
 int fit_image_hash_get_algo(const void *fit, int noffset, char **algo);
 int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
@@ -1186,6 +1188,7 @@  int calculate_hash(const void *data, int data_len, const char *algo,
  * device
  */
 #if defined(USE_HOSTCC)
+# define IMAGE_ENABLE_ARBP	0
 # if defined(CONFIG_FIT_SIGNATURE)
 #  define IMAGE_ENABLE_SIGN	1
 #  define IMAGE_ENABLE_VERIFY	1
@@ -1200,6 +1203,7 @@  int calculate_hash(const void *data, int data_len, const char *algo,
 # define IMAGE_ENABLE_SIGN	0
 # define IMAGE_ENABLE_VERIFY		CONFIG_IS_ENABLED(RSA_VERIFY)
 # define FIT_IMAGE_ENABLE_VERIFY	CONFIG_IS_ENABLED(FIT_SIGNATURE)
+# define IMAGE_ENABLE_ARBP		CONFIG_IS_ENABLED(FIT_ARBP)
 #endif
 
 #if IMAGE_ENABLE_FIT
@@ -1544,6 +1548,25 @@  int board_fit_config_name_match(const char *name);
 void board_fit_image_post_process(void **p_image, size_t *p_size);
 #endif /* CONFIG_SPL_FIT_IMAGE_POST_PROCESS */
 
+#if defined(CONFIG_FIT_ARBP)
+/**
+ * board_get_arbvn() - get the arbvn stored in the platform secure storage.
+ *
+ * @ih_type: image type
+ * @arbvn: pointer to the arbvn
+ * @return 0 if upon successful retrieval, non-zero upon failure.
+ */
+int board_get_arbvn(uint8_t ih_type, uint32_t *arbvn);
+/**
+ * board_set_arbvn() - set the arbvn stored in the platform secure storage.
+ *
+ * @ih_type: image type
+ * @arbvn: new arbvn value to store in the platform secure storage.
+ * @return 0 if stored successfully, non-zero upon failure.
+ */
+int board_set_arbvn(uint8_t ih_type, uint32_t arbvn);
+#endif /* CONFIG_FIT_ARBP */
+
 #define FDT_ERROR	((ulong)(-1))
 
 ulong fdt_getprop_u32(const void *fdt, int node, const char *prop);