summaryrefslogtreecommitdiff
path: root/nrfdemo/builddk/tfm/api_ns/platform/common/nrf_provisioning.c
blob: 4ce7792e1f60890c0ac7909ff9f09f9c674d2527 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Copyright (c) 2022 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include "tfm_plat_provisioning.h"
#include "tfm_plat_otp.h"
#include "tfm_platform_system.h"
#include "tfm_attest_hal.h"
#include "hw_unique_key.h"
#include "nrfx_nvmc.h"
#include <nrfx.h>
#include <nrf_cc3xx_platform.h>
#include <nrf_cc3xx_platform_identity_key.h>
#include "nrf_provisioning.h"
#include <identity_key.h>
#include <tfm_spm_log.h>

static enum tfm_plat_err_t disable_debugging(void)
{
	/* Configure the UICR such that upon the next reset, APPROTECT will be enabled */
	bool approt_writable;

	approt_writable = nrfx_nvmc_word_writable_check((uint32_t)&NRF_UICR_S->APPROTECT,
							UICR_APPROTECT_PALL_Protected);
	approt_writable &= nrfx_nvmc_word_writable_check((uint32_t)&NRF_UICR_S->SECUREAPPROTECT,
							 UICR_SECUREAPPROTECT_PALL_Protected);

	if (approt_writable) {
		nrfx_nvmc_word_write((uint32_t)&NRF_UICR_S->APPROTECT,
				     UICR_APPROTECT_PALL_Protected);
		nrfx_nvmc_word_write((uint32_t)&NRF_UICR_S->SECUREAPPROTECT,
				     UICR_SECUREAPPROTECT_PALL_Protected);
	} else {
		return TFM_PLAT_ERR_SYSTEM_ERR;
	}

	return TFM_PLAT_ERR_SUCCESS;
}

int tfm_plat_provisioning_is_required(void)
{
	enum tfm_security_lifecycle_t lcs;

	lcs = tfm_attest_hal_get_security_lifecycle();

	return lcs == TFM_SLC_PSA_ROT_PROVISIONING;
}

enum tfm_plat_err_t tfm_plat_provisioning_perform(void)
{
	enum tfm_security_lifecycle_t lcs;

	lcs = tfm_attest_hal_get_security_lifecycle();

	/*
	 * Provisioning in NRF defines has two steps, the first step is to execute
	 * the provisioning_image sample. When this sample is executed it will
	 * always set the lifecycle state to PROVISIONING. This is a requirement for
	 * the TF-M provisioning to be completed so we don't accept any other
	 * lifecycle state here.
	 */

	/* The Hardware Unique Keys should be already written */
	if (!hw_unique_key_are_any_written()) {
		SPMLOG_ERRMSG("This device has not been provisioned with Hardware Unique Keys.");
		return TFM_PLAT_ERR_SYSTEM_ERR;
	}

#ifdef TFM_PARTITION_INITIAL_ATTESTATION
	/* The Initial Attestation key should be already written */
	if (!identity_key_is_written()) {
		SPMLOG_ERRMSG(
			"This device has not been provisioned with an Initial Attestation Key.");
		return TFM_PLAT_ERR_SYSTEM_ERR;
	}
#endif

	/*
	 * We don't need to make sure that the validation key is written here since we assume
	 * that secure boot is already enabled at this stage
	 */

	/* Disable debugging in UICR */
	if (disable_debugging() != TFM_PLAT_ERR_SUCCESS) {
		return TFM_PLAT_ERR_SYSTEM_ERR;
	}

	/* Transition to the SECURED lifecycle state */
	if (tfm_attest_update_security_lifecycle_otp(TFM_SLC_SECURED) != 0) {
		return TFM_PLAT_ERR_SYSTEM_ERR;
	}

	lcs = tfm_attest_hal_get_security_lifecycle();
	if (lcs != TFM_SLC_SECURED) {
		return TFM_PLAT_ERR_SYSTEM_ERR;
	}

	/* Perform a mandatory reset since we switch to an attestable LCS state */
	tfm_platform_hal_system_reset();

	/*
	 * We should never return from this function, a reset should be triggered
	 * before we reach this point. Returning an error to signal that something
	 * is wrong if we reached here.
	 */
	return TFM_PLAT_ERR_SYSTEM_ERR;
}

static bool dummy_key_is_present(void)
{
#ifdef TFM_PARTITION_INITIAL_ATTESTATION
	uint8_t key[IDENTITY_KEY_SIZE_BYTES];
	int err;

	err = identity_key_read(key);
	if (err < 0) {
		/* Unable to read out the key. Then it is likely not present. */
		return false;
	}

	/* The first 8 bytes of the dummy key */
	uint8_t first_8_bytes[8] = {0xA9, 0xB4, 0x54, 0xB2, 0x6D, 0x6F, 0x90, 0xA4};

	/* Check if any bytes differ */
	for (int i = 0; i < 8; i++) {
		if (key[i] != first_8_bytes[i]) {
			return false;
		}
	}

	/* The first 8 bytes matched the dummy key, so it is most likely the dummy key */
	return true;
#else
	return false;
#endif
}

void tfm_plat_provisioning_check_for_dummy_keys(void)
{
	if (dummy_key_is_present()) {
		SPMLOG_ERRMSG("This device was provisioned with dummy keys and is NOT secure.");
	}
}