Platform: Get attestation private key from OTP on Musca-B1

Change-Id: I3059bc09b1fd07631e0c0213dc176773cdc4a7e5
Signed-off-by: Xu Yong <yong.xu@arm.com>
diff --git a/platform/ext/common/cc312/cc312.c b/platform/ext/common/cc312/cc312.c
index f1a65e3..29fe268 100644
--- a/platform/ext/common/cc312/cc312.c
+++ b/platform/ext/common/cc312/cc312.c
@@ -17,6 +17,8 @@
 #include "arm_cmse.h"
 #include "mbedtls_cc_util_key_derivation.h"
 #include "tfm_attest_hal.h"
+#include "prod_hw_defs.h"
+#include "cc_otp_defs.h"
 
 #define CC312_NULL_CONTEXT "NO SALT!"
 
@@ -127,7 +129,79 @@
                                             label, label_size,
                                             context, context_size,
                                             key, key_size);
+}
 
+/*
+ * Count number of zero bits in 32-bit word.
+ * Copied from:
+ * lib/ext/cryptocell-312-runtime/host/src/ \
+ * cc3x_productionlib/common/prod_util.c: CC_PROD_GetZeroCount(..)
+ */
+static int get_zero_bits_count(uint32_t *buf,
+                               uint32_t  buf_word_size,
+                               uint32_t *zero_count)
+{
+    uint32_t val;
+    uint32_t index = 0;
+
+    *zero_count = 0;
+    for (index = 0; index < buf_word_size; index++) {
+        val = buf[index];
+        val = val - ((val >> 1) & 0x55555555);
+        val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+        val = ((((val + (val >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
+        *zero_count += (32 - val);
+    }
+    /* All 0's and all 1's is forbidden */
+    if ((*zero_count == 0)
+        || (*zero_count == buf_word_size*CC_BITS_IN_32BIT_WORD)) {
+        *zero_count = 0;
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Get attestation private key from CC312 OTP
+ */
+int crypto_hw_accelerator_get_attestation_private_key(uint8_t  *buf,
+                                                      uint32_t *size)
+{
+    uint32_t *key = (uint32_t *)buf;
+    uint32_t otp_val;
+    uint32_t otp_zero_count;
+    uint32_t zero_count;
+    int i;
+    int rc;
+
+    if (key == NULL ||
+        *size < CC_OTP_ATTESTATION_KEY_SIZE_IN_WORDS * sizeof(uint32_t)) {
+        return -1;
+    }
+    *size = CC_OTP_ATTESTATION_KEY_SIZE_IN_WORDS * sizeof(uint32_t);
+
+    /* Get provisioned key from OTP, 8 words */
+    for (i = 0; i < CC_OTP_ATTESTATION_KEY_SIZE_IN_WORDS; i++) {
+        CC_PROD_OTP_READ(otp_val, CC_OTP_ATTESTATION_KEY_OFFSET + i);
+        *key = otp_val;
+        key++;
+    }
+
+    /* Verify the zero number of private key */
+    rc = get_zero_bits_count((uint32_t *)buf,
+                             CC_OTP_ATTESTATION_KEY_SIZE_IN_WORDS,
+                             &zero_count);
+    if (rc) {
+        return -1;
+    }
+
+    CC_PROD_OTP_READ(otp_zero_count, CC_OTP_ATTESTATION_KEY_ZERO_COUNT_OFFSET);
+    if (otp_zero_count != zero_count) {
+        return -1;
+    }
+
+    return 0;
 }
 
 int crypto_hw_accelerator_get_rotpk_hash(uint8_t image_id,
diff --git a/platform/ext/common/cc312/crypto_hw.h b/platform/ext/common/cc312/crypto_hw.h
index d3c513d..d4c7aaf 100644
--- a/platform/ext/common/cc312/crypto_hw.h
+++ b/platform/ext/common/cc312/crypto_hw.h
@@ -88,6 +88,18 @@
                                          uint32_t *rotpk_hash_size);
 
 /**
+ * \brief Retrieve the attestation private key from OTP
+ *
+ * \param[out]     buf   Buffer to store the key in
+ * \param[in,out]  size  As input the size of the buffer. As output the actual
+ *                       size of the key in bytes.
+ *
+ * \return 0 on success, non-zero otherwise
+ */
+int crypto_hw_accelerator_get_attestation_private_key(uint8_t *buf,
+                                                      uint32_t *size);
+
+/**
  * \brief Retrieve the device lifecycle
  *
  * \param[out]  lcs  Pointer to store lifecycle state
diff --git a/platform/ext/target/musca_b1/dummy_crypto_keys.c b/platform/ext/target/musca_b1/dummy_crypto_keys.c
index 4af3404..83e768f 100644
--- a/platform/ext/target/musca_b1/dummy_crypto_keys.c
+++ b/platform/ext/target/musca_b1/dummy_crypto_keys.c
@@ -45,6 +45,7 @@
 extern const struct tfm_plat_rotpk_t device_rotpk[];
 extern const uint32_t rotpk_key_cnt;
 
+#ifndef CRYPTO_HW_ACCELERATOR_OTP_ENABLED
 /**
  * \brief Copy the key to the destination buffer
  *
@@ -62,6 +63,7 @@
         p_dst++;
     }
 }
+#endif /* !CRYPTO_HW_ACCELERATOR_OTP_ENABLED */
 
 enum tfm_plat_err_t tfm_plat_get_huk_derived_key(const uint8_t *label,
                                                  size_t label_size,
@@ -110,12 +112,10 @@
                                 struct ecc_key_t *ecc_key,
                                 psa_ecc_curve_t  *curve_type)
 {
-    uint8_t *key_dst;
-    const uint8_t *key_src;
-    uint32_t key_size;
-    uint32_t full_key_size = initial_attestation_private_key_size;
+    uint32_t key_size = initial_attestation_private_key_size;
+    int rc;
 
-    if (size < full_key_size) {
+    if (size < key_size) {
         return TFM_PLAT_ERR_SYSTEM_ERR;
     }
 
@@ -123,11 +123,19 @@
     *curve_type = initial_attestation_curve_type;
 
     /* Copy the private key to the buffer, it MUST be present */
-    key_dst  = key_buf;
-    key_src  = initial_attestation_private_key;
-    key_size = initial_attestation_private_key_size;
-    copy_key(key_dst, key_src, key_size);
-    ecc_key->priv_key = key_dst;
+#ifdef CRYPTO_HW_ACCELERATOR_OTP_ENABLED
+    rc = crypto_hw_accelerator_get_attestation_private_key(key_buf, &size);
+    key_size = size;
+#else
+    copy_key(key_buf, initial_attestation_private_key, key_size);
+    rc = 0;
+#endif /* CRYPTO_HW_ACCELERATOR_OTP_ENABLED */
+
+    if (rc) {
+        return TFM_PLAT_ERR_SYSTEM_ERR;
+    }
+
+    ecc_key->priv_key = key_buf;
     ecc_key->priv_key_size = key_size;
 
     ecc_key->pubx_key = NULL;