diff --git a/docs/porting-guide.md b/docs/porting-guide.md index bd1b448..6c0501f 100644 --- a/docs/porting-guide.md +++ b/docs/porting-guide.md @@ -638,6 +638,35 @@ to the ROTPK in the flags parameter. +### Function: plat_get_nv_ctr() + + Argument : void *, unsigned int * + Return : int + +This function is mandatory when Trusted Board Boot is enabled. It returns the +non-volatile counter value stored in the platform in the second argument. The +cookie in the first argument may be used to select the counter in case the +platform provides more than one (for example, on platforms that use the default +TBBR CoT, the cookie will correspond to the OID values defined in +TRUSTED_FW_NVCOUNTER_OID or NON_TRUSTED_FW_NVCOUNTER_OID). + +The function returns 0 on success. Any other value means the counter value could +not be retrieved from the platform. + + +### Function: plat_set_nv_ctr() + + Argument : void *, unsigned int + Return : int + +This function is mandatory when Trusted Board Boot is enabled. It sets a new +counter value in the platform. The cookie in the first argument may be used to +select the counter (as explained in plat_get_nv_ctr()). + +The function returns 0 on success. Any other value means the counter value could +not be updated. + + 2.3 Common mandatory modifications --------------------------------- diff --git a/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c index bdd3c5a..4184556 100644 --- a/drivers/auth/auth_mod.c +++ b/drivers/auth/auth_mod.c @@ -40,6 +40,9 @@ #include #include +/* ASN.1 tags */ +#define ASN1_INTEGER 0x02 + #define return_if_error(rc) \ do { \ if (rc != 0) { \ @@ -227,6 +230,83 @@ } /* + * Authenticate by Non-Volatile counter + * + * 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. + * + * Return: 0 = success, Otherwise = error + */ +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) +{ + char *p; + void *data_ptr = NULL; + unsigned int data_len, len, i; + unsigned int cert_nv_ctr, plat_nv_ctr; + int rc = 0; + + /* Get the counter value from current image. The AM expects the IPM + * to return the counter value as a DER encoded integer */ + rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr, + img, img_len, &data_ptr, &data_len); + return_if_error(rc); + + /* Parse the DER encoded integer */ + assert(data_ptr); + p = (char *)data_ptr; + if (*p != ASN1_INTEGER) { + /* Invalid ASN.1 integer */ + return 1; + } + p++; + + /* NV-counters are unsigned integers up to 32-bit */ + len = (unsigned int)(*p & 0x7f); + if ((*p & 0x80) || (len > 4)) { + return 1; + } + p++; + + /* Check the number is not negative */ + if (*p & 0x80) { + return 1; + } + + /* Convert to unsigned int. This code is for a little-endian CPU */ + cert_nv_ctr = 0; + for (i = 0; i < len; i++) { + 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) { + /* Invalid NV-counter */ + return 1; + } else if (cert_nv_ctr > plat_nv_ctr) { + if (img_desc->parent == NULL) { + /* This certificate has been signed with the ROT key. + * Update the platform counter value */ + rc = plat_set_nv_ctr(param->plat_nv_ctr->cookie, + cert_nv_ctr); + return_if_error(rc); + } else { + /* Secondary certificates cannot modify the counter */ + return 1; + } + } + + return 0; +} + +/* * Return the parent id in the output parameter '*parent_id' * * Return value: @@ -310,6 +390,10 @@ rc = auth_signature(&auth_method->param.sig, img_desc, img_ptr, img_len); break; + case AUTH_METHOD_NV_CTR: + rc = auth_nvctr(&auth_method->param.nv_ctr, + img_desc, img_ptr, img_len); + break; default: /* Unknown authentication method */ rc = 1; diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c index 52e6971..1a6a9a7 100644 --- a/drivers/auth/mbedtls/mbedtls_x509_parser.c +++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c @@ -405,6 +405,13 @@ /* * Extract an authentication parameter from an X509v3 certificate + * + * This function returns a pointer to the extracted data and its length. + * Depending on the type of parameter, a pointer to the data stored in the + * certificate may be returned (i.e. an octet string containing a hash). Other + * data may need to be copied and formatted (i.e. integers). In the later case, + * a buffer of the correct type needs to be statically allocated, filled and + * returned. */ static int get_auth_param(const auth_param_type_desc_t *type_desc, void *img, unsigned int img_len, @@ -422,6 +429,7 @@ *param_len = (unsigned int)tbs.len; break; case AUTH_PARAM_HASH: + case AUTH_PARAM_NV_CTR: /* All these parameters are included as X509v3 extensions */ rc = get_ext(type_desc->cookie, param, param_len); break; diff --git a/drivers/auth/tbbr/tbbr_cot.c b/drivers/auth/tbbr/tbbr_cot.c index 6023c78..dae35d1 100644 --- a/drivers/auth/tbbr/tbbr_cot.c +++ b/drivers/auth/tbbr/tbbr_cot.c @@ -56,6 +56,11 @@ /* * Parameter type descriptors */ +static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID); +static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC( + AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID); + static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, 0); static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC( @@ -116,6 +121,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -158,6 +170,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -193,6 +212,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -218,6 +244,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -260,6 +293,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -285,6 +325,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -327,6 +374,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -352,6 +406,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &trusted_nv_ctr, + .plat_nv_ctr = &trusted_nv_ctr + } } }, .authenticated_data = { @@ -394,6 +455,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &non_trusted_nv_ctr, + .plat_nv_ctr = &non_trusted_nv_ctr + } } }, .authenticated_data = { @@ -419,6 +487,13 @@ .alg = &sig_alg, .data = &raw_data, } + }, + [1] = { + .type = AUTH_METHOD_NV_CTR, + .param.nv_ctr = { + .cert_nv_ctr = &non_trusted_nv_ctr, + .plat_nv_ctr = &non_trusted_nv_ctr + } } }, .authenticated_data = { diff --git a/include/drivers/auth/auth_common.h b/include/drivers/auth/auth_common.h index 52a895e..456f69f 100644 --- a/include/drivers/auth/auth_common.h +++ b/include/drivers/auth/auth_common.h @@ -46,6 +46,7 @@ AUTH_PARAM_SIG_ALG, /* The image signature algorithm */ AUTH_PARAM_HASH, /* A hash (including the algorithm) */ AUTH_PARAM_PUB_KEY, /* A public key */ + AUTH_PARAM_NV_CTR, /* A non-volatile counter */ } auth_param_type_t; /* @@ -80,6 +81,7 @@ AUTH_METHOD_NONE = 0, AUTH_METHOD_HASH, /* Authenticate by hash matching */ AUTH_METHOD_SIG, /* Authenticate by PK operation */ + AUTH_METHOD_NV_CTR, /* Authenticate by Non-Volatile Counter */ AUTH_METHOD_NUM /* Number of methods */ } auth_method_type_t; @@ -105,7 +107,8 @@ * Parameters for authentication by NV counter */ typedef struct auth_method_param_nv_ctr_s { - auth_param_type_desc_t *nv_ctr; /* NV counter value */ + auth_param_type_desc_t *cert_nv_ctr; /* NV counter in certificate */ + auth_param_type_desc_t *plat_nv_ctr; /* NV counter in platform */ } auth_method_param_nv_ctr_t; /* diff --git a/include/plat/arm/soc/common/soc_css_def.h b/include/plat/arm/soc/common/soc_css_def.h index 428df4d..f1396a6 100644 --- a/include/plat/arm/soc/common/soc_css_def.h +++ b/include/plat/arm/soc/common/soc_css_def.h @@ -65,6 +65,13 @@ */ #define SOC_CSS_NIC400_APB4_BRIDGE 4 +/* Non-volatile counters */ +#define SOC_TRUSTED_NVCTR_BASE 0x7fe70000 +#define TFW_NVCTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0000) +#define TFW_NVCTR_SIZE 4 +#define NTFW_CTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0004) +#define NTFW_CTR_SIZE 4 + /* Keys */ #define SOC_KEYS_BASE 0x7fe80000 #define TZ_PUB_KEY_HASH_BASE (SOC_KEYS_BASE + 0x0000) diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index 5c61f38..f4d91df 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -249,6 +249,8 @@ ******************************************************************************/ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags); +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr); +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr); #if ENABLE_PLAT_COMPAT /* diff --git a/plat/arm/board/common/board_arm_trusted_boot.c b/plat/arm/board/common/board_arm_trusted_boot.c index 103aafb..7ae00cc 100644 --- a/plat/arm/board/common/board_arm_trusted_boot.c +++ b/plat/arm/board/common/board_arm_trusted_boot.c @@ -31,11 +31,14 @@ #include #include #include +#include #include #include /* Weak definition may be overridden in specific platform */ #pragma weak plat_match_rotpk +#pragma weak plat_get_nv_ctr +#pragma weak plat_set_nv_ctr /* SHA256 algorithm */ #define SHA256_BYTES 32 @@ -148,3 +151,43 @@ return 0; } +/* + * Return the non-volatile counter value stored in the platform. The cookie + * will contain the OID of the counter in the certificate. + * + * Return: 0 = success, Otherwise = error + */ +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) +{ + const char *oid; + uint32_t *nv_ctr_addr; + + assert(cookie != NULL); + assert(nv_ctr != NULL); + + oid = (const char *)cookie; + if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) { + nv_ctr_addr = (uint32_t *)TFW_NVCTR_BASE; + } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) { + nv_ctr_addr = (uint32_t *)NTFW_CTR_BASE; + } else { + return 1; + } + + *nv_ctr = (unsigned int)(*nv_ctr_addr); + + return 0; +} + +/* + * Store a new non-volatile counter value. On Juno and FVP, the non-volatile + * counters are RO and cannot be modified. We expect the values in the + * certificates to always match the RO values so that this function is never + * called. + * + * Return: 0 = success, Otherwise = error + */ +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) +{ + return 1; +} diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk index da6beec..6ddc0c9 100644 --- a/plat/arm/board/common/board_common.mk +++ b/plat/arm/board/common/board_common.mk @@ -51,6 +51,11 @@ endif $(eval $(call add_define,ARM_ROTPK_LOCATION_ID)) + # Certificate NV-Counters. Use values corresponding to tied off values in + # ARM development platforms + TFW_NVCTR_VAL ?= 31 + NTFW_NVCTR_VAL ?= 223 + BL1_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c BL2_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c endif diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h index dbca280..b0f07ef 100644 --- a/plat/arm/board/fvp/fvp_def.h +++ b/plat/arm/board/fvp/fvp_def.h @@ -69,7 +69,13 @@ #define PCIE_EXP_BASE 0x40000000 #define TZRNG_BASE 0x7fe60000 -#define TZNVCTR_BASE 0x7fe70000 + +/* Non-volatile counters */ +#define TRUSTED_NVCTR_BASE 0x7fe70000 +#define TFW_NVCTR_BASE (TRUSTED_NVCTR_BASE + 0x0000) +#define TFW_NVCTR_SIZE 4 +#define NTFW_CTR_BASE (TRUSTED_NVCTR_BASE + 0x0004) +#define NTFW_CTR_SIZE 4 /* Keys */ #define SOC_KEYS_BASE 0x7fe80000