Add Broadcom / Netgear changes from RAXE 1.0.0.48
[project/bcm63xx/u-boot.git] / board / broadcom / bcmbca / board_secure_fit.c
diff --git a/board/broadcom/bcmbca/board_secure_fit.c b/board/broadcom/bcmbca/board_secure_fit.c
new file mode 100644 (file)
index 0000000..ce4cd46
--- /dev/null
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 Broadcom Ltd.
+ */
+#include <common.h>
+#include <fdtdec.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <asm/unaligned.h>
+#include <malloc.h>
+#include "tpl_params.h"
+#include "spl_env.h"
+#include "u-boot/rsa.h"
+#include "u-boot/rsa-mod-exp.h"
+#include <u-boot/sha256.h>
+#include <uboot_aes.h>
+#include <watchdog.h>
+#include "bcm_secure.h"
+
+#define FIT_PAD_MAX_SIZE 0x1000
+#define BCM_TAG_FIT_HDR_SEC_DELG_REC    0x44454c47 // DELG
+#define BCM_TAG_FIT_HDR_SEC_SIGNATURE  0x46495453 // FITS
+#define BCM_TAG_FIT_HDR_SEC_PUBKEY     0x46495450 // FITP
+#define BCM_FIT_HDR_MAX_RECORDS                4       
+#define BCM_FIT_HDR_MIN_HDR_SIZE       (RSA2048_BYTES+sizeof(u32))
+
+int bcm_tag_fit_hdr_validate(const u8 *fit, u32 size, 
+               u32 hdr_size, u8* master_pub)
+{
+       int rc = -1;
+       u32 tag = 0, cnt = 0;
+       u8 sig[RSA2048_BYTES];
+       u8 *p = (u8*)fit + size;
+       u8 *pmax = p; 
+       u8 key_buf[RSA2048_BYTES];
+       const u8 *key = master_pub;
+       struct image_sign_info im;
+
+#if defined (CONFIG_TPL_BUILD)
+       u32 sdr_plus_sig_size = 0;
+       int sdr_verified = 0;
+#endif         
+
+       if (hdr_size < BCM_FIT_HDR_MIN_HDR_SIZE) {
+               goto err;
+       }       
+       
+       im.checksum = image_get_checksum_algo("sha256,");
+       if (!im.checksum) {
+               printf("ERROR: couldn't get checksum algo\n"); 
+               goto err;
+       }
+       while (cnt < BCM_FIT_HDR_MAX_RECORDS && (p - pmax) < hdr_size) {
+               memcpy(&tag, p, sizeof(u32));
+               switch ( tag ) {
+#if defined (CONFIG_TPL_BUILD)
+                       case BCM_TAG_FIT_HDR_SEC_DELG_REC:
+                               rc = bcm_sec_delg_process_sdr(p, pmax+hdr_size-1, &sdr_plus_sig_size);
+                               if( rc ) {
+                                       printf("ERROR: SDR verification failed!\n");
+                                       return rc;
+                               } else {
+                                       /* SDR valid, swap in new pub key */
+                                       key = bcm_sec_get_active_pub_key();
+                                       p += sdr_plus_sig_size; 
+                                       sdr_verified = 1;
+                               }
+                       break;
+#endif /* defined (CONFIG_TPL_BUILD) */
+                       case BCM_TAG_FIT_HDR_SEC_SIGNATURE:
+                               memcpy(sig, p + sizeof(u32), RSA2048_BYTES);
+                               debug("\nVerifying Signature; 4 leading bytes 0x%x verifying with key 0x%x\n",*(u32*)sig, *(u32*)key);
+                               if (!bcm_sec_rsa_verify(fit, size, sig,  RSA2048_BYTES, key, &im )) {
+                                       rc = 0;
+#if defined (CONFIG_TPL_BUILD)
+                                       /* Upon FIT hdr & sdr authentication success, check sec node */
+                                       if( sdr_verified ) {
+                                               rc = bcm_sec_delg_process_sec_node(fit);
+                                               if( rc ) {
+                                                       printf("ERROR: Security Node verification failed!\n");
+                                               }
+                                       }
+#endif /* defined (CONFIG_TPL_BUILD) */
+                                       return rc;
+                               }
+                               p += sizeof(u32) + RSA2048_BYTES; 
+                       break;
+                       case BCM_TAG_FIT_HDR_SEC_PUBKEY:
+#if defined (CONFIG_TPL_BUILD)
+                               if( !sdr_verified ) 
+#endif                                 
+                               {
+                                       memcpy(key_buf, p + sizeof(u32), RSA2048_BYTES);
+                                       memcpy(sig, p + sizeof(u32) + RSA2048_BYTES , RSA2048_BYTES);
+                                       debug("\nGot Key and Signature, 4 leading bytes: key 0x%x sig 0x%x\n", 
+                                                       *(u32*)key_buf, *(u32*)sig);
+                                       if (!bcm_sec_rsa_verify(key_buf, RSA2048_BYTES, sig,  RSA2048_BYTES, master_pub, &im )) {
+                                               key = key_buf; 
+                                       } else {
+                                               printf("The key 0x%x can't be verified\n", *(u32*)key_buf);
+                                       } 
+
+                                       p += sizeof(u32) + RSA2048_BYTES*2;
+                                       cnt++; 
+                               }
+                       break;
+                       default:
+                               p++;
+               }
+       } 
+err:
+       return rc;
+}
+
+ulong bcm_sec_get_reqd_load_size( void * fit )
+{
+       return( fdt_totalsize(fit) + FIT_PAD_MAX_SIZE );
+}
+
+int bcm_sec_validate_fit(void* fit, u32 max_image_size)
+{
+       int rc = -1;
+       ulong size = fdt_totalsize(fit);
+       bcm_sec_state_t st = bcm_sec_state();
+
+       if (FIT_PAD_MAX_SIZE > max_image_size) {
+               printf("ERROR: FIT image is too short to process\n");
+               goto _die;
+       }
+
+       u8* key = bcm_sec_get_active_pub_key();
+       if (!key) {
+               if((st == SEC_STATE_UNSEC)) {
+                       rc = 0;
+               }
+               goto _die;
+       }
+
+       rc = bcm_tag_fit_hdr_validate(fit, size, FIT_PAD_MAX_SIZE, (u8*)key);
+       if (rc) {
+               goto _die;
+       }
+       rc = 0;
+       printf("FIT Header Authentication Successfull!\n");
+_die:
+       if(rc ) {
+               printf("FAILED to authenticate FIT header!!! \n");
+               if(st & SEC_STATE_SECURE) {
+                       bcm_sec_abort();
+               } 
+       }
+       return rc; 
+}
+
+u8* bcm_util_get_fdt_prop_data(void* fdt, char* path, char *prop, int* len)
+{
+       u8* d = NULL; 
+       int node = fdt_path_offset (fdt, path);
+       if(node < 0) {
+               debug("ERROR: unable to find path fdt %s \n", path);
+               goto err;
+       } 
+       d = (u8*)fdt_getprop(fdt, node, prop, len);
+       if (!d) {
+               debug("ERROR: unable to get %s\n", prop);
+               goto err;
+       }
+err :
+       return d;
+}