cryptocell_crypto.c 8.06 KB
Newer Older
1
/*
2
 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
3
4
5
6
7
8
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stddef.h>
#include <string.h>
9
10
11
12
13

#include <platform_def.h>

#include <arch_helpers.h>
#include <common/debug.h>
14
15
16
17
18
19
#include <drivers/arm/cryptocell/712/crypto_driver.h>
#include <drivers/arm/cryptocell/712/rsa.h>
#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
#include <drivers/arm/cryptocell/712/secureboot_base_func.h>
#include <drivers/arm/cryptocell/712/secureboot_gen_defs.h>
#include <drivers/arm/cryptocell/712/util.h>
20
21
22
#include <drivers/auth/crypto_mod.h>
#include <drivers/auth/mbedtls/mbedtls_common.h>
#include <lib/utils.h>
23
24
25

#include <mbedtls/oid.h>

26
#define LIB_NAME		"CryptoCell 712 SBROM"
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
#define RSA_SALT_LEN		32
#define RSA_EXPONENT		65537

/*
 * AlgorithmIdentifier  ::=  SEQUENCE  {
 *     algorithm            OBJECT IDENTIFIER,
 *     parameters           ANY DEFINED BY algorithm OPTIONAL
 * }
 *
 * SubjectPublicKeyInfo  ::=  SEQUENCE  {
 *     algorithm            AlgorithmIdentifier,
 *     subjectPublicKey     BIT STRING
 * }
 *
 * DigestInfo ::= SEQUENCE {
 *     digestAlgorithm      AlgorithmIdentifier,
 *     digest               OCTET STRING
 * }
 *
 *  RSASSA-PSS-params ::= SEQUENCE {
 *     hashAlgorithm        [0] HashAlgorithm,
 *     maskGenAlgorithm     [1] MaskGenAlgorithm,
 *     saltLength           [2] INTEGER,
 *     trailerField         [3] TrailerField    DEFAULT trailerFieldBC
 * }
 */

/*
 * Initialize the library and export the descriptor
 */
static void init(void)
{
	CCError_t ret;
Soby Mathew's avatar
Soby Mathew committed
60
	uint32_t lcs;
61
62
63
64
65
66
67

	/* Initialize CC SBROM */
	ret = CC_BsvSbromInit((uintptr_t)PLAT_CRYPTOCELL_BASE);
	if (ret != CC_OK) {
		ERROR("CryptoCell CC_BsvSbromInit() error %x\n", ret);
		panic();
	}
Soby Mathew's avatar
Soby Mathew committed
68
69
70
71
72
73
74
75
76
77
78
79
80

	/* Initialize lifecycle state */
	ret = CC_BsvLcsGetAndInit((uintptr_t)PLAT_CRYPTOCELL_BASE, &lcs);
	if (ret != CC_OK) {
		ERROR("CryptoCell CC_BsvLcsGetAndInit() error %x\n", ret);
		panic();
	}

	/* If the lifecyclestate is `SD`, then stop further execution */
	if (lcs == CC_BSV_SECURITY_DISABLED_LCS) {
		ERROR("CryptoCell LCS is security-disabled\n");
		panic();
	}
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
}

/*
 * Verify a signature.
 *
 * Parameters are passed using the DER encoding format following the ASN.1
 * structures detailed above.
 */
static int verify_signature(void *data_ptr, unsigned int data_len,
			    void *sig_ptr, unsigned int sig_len,
			    void *sig_alg, unsigned int sig_alg_len,
			    void *pk_ptr, unsigned int pk_len)
{
	CCError_t error;
	CCSbNParams_t pk;
	CCSbSignature_t signature;
	int rc, exp;
	mbedtls_asn1_buf sig_oid, alg_oid, params;
	mbedtls_md_type_t md_alg;
	mbedtls_pk_type_t pk_alg;
	mbedtls_pk_rsassa_pss_options pss_opts;
	size_t len;
	uint8_t *p, *end;
	/* Temp buf to store the public key modulo (N) in LE format */
	uint32_t RevN[SB_RSA_MOD_SIZE_IN_WORDS];

	/* Verify the signature algorithm */
	/* Get pointers to signature OID and parameters */
	p = sig_alg;
	end = p + sig_alg_len;
	rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &params);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	/* Get the actual signature algorithm (MD + PK) */
	rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	/* The CryptoCell only supports RSASSA-PSS signature */
	if (pk_alg != MBEDTLS_PK_RSASSA_PSS || md_alg != MBEDTLS_MD_NONE)
		return CRYPTO_ERR_SIGNATURE;

	/* Verify the RSASSA-PSS params */
	/* The trailer field is verified to be 0xBC internally by this API */
	rc = mbedtls_x509_get_rsassa_pss_params(&params, &md_alg,
			&pss_opts.mgf1_hash_id,
			&pss_opts.expected_salt_len);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	/* The CryptoCell only supports SHA256 as hash algorithm */
	if (md_alg != MBEDTLS_MD_SHA256 || pss_opts.mgf1_hash_id != MBEDTLS_MD_SHA256)
		return CRYPTO_ERR_SIGNATURE;

	if (pss_opts.expected_salt_len != RSA_SALT_LEN)
		return CRYPTO_ERR_SIGNATURE;

	/* Parse the public key */
	p = pk_ptr;
	end = p + pk_len;
	rc = mbedtls_asn1_get_tag(&p, end, &len,
			MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	end = p + len;
	rc = mbedtls_asn1_get_alg_null(&p, end, &alg_oid);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	if (mbedtls_oid_get_pk_alg(&alg_oid, &pk_alg) != 0)
		return CRYPTO_ERR_SIGNATURE;

	if (pk_alg != MBEDTLS_PK_RSA)
		return CRYPTO_ERR_SIGNATURE;

	rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	rc = mbedtls_asn1_get_tag(&p, end, &len,
				MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	if (*p == 0) {
		p++; len--;
	}
	if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end))
		return CRYPTO_ERR_SIGNATURE;

	/*
	 * The CCSbVerifySignature() API expects N and Np in BE format and
	 * the signature in LE format. Copy N from certificate.
	 */
	memcpy(pk.N, p, RSA_MOD_SIZE_IN_BYTES);

	/* Verify the RSA exponent */
	p += len;
	rc = mbedtls_asn1_get_int(&p, end, &exp);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	if (exp != RSA_EXPONENT)
		return CRYPTO_ERR_SIGNATURE;

	/*
	 * Calculate the Np (Barrett n' value). The RSA_CalcNp() API expects
	 * N in LE format. Hence reverse N into a temporary buffer `RevN`.
	 */
	UTIL_ReverseMemCopy((uint8_t *)RevN, (uint8_t *)pk.N, sizeof(RevN));

	RSA_CalcNp((uintptr_t)PLAT_CRYPTOCELL_BASE, RevN, pk.Np);

	/* Np is in LE format. Reverse it to BE */
	UTIL_ReverseBuff((uint8_t *)pk.Np, sizeof(pk.Np));

	/* Get the signature (bitstring) */
	p = sig_ptr;
	end = p + sig_len;
	rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
	if (rc != 0)
		return CRYPTO_ERR_SIGNATURE;

	if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end))
		return CRYPTO_ERR_SIGNATURE;

	/*
	 *  The signature is BE format. Convert it to LE before calling
	 *  CCSbVerifySignature().
	 */
	UTIL_ReverseMemCopy((uint8_t *)signature.sig, p, RSA_MOD_SIZE_IN_BYTES);

	/*
	 * CryptoCell utilises DMA internally to transfer data. Flush the data
	 * from caches.
	 */
	flush_dcache_range((uintptr_t)data_ptr, data_len);

	/* Verify the signature */
	error = CCSbVerifySignature((uintptr_t)PLAT_CRYPTOCELL_BASE,
			(uint32_t *)data_ptr, &pk, &signature,
			data_len, RSA_PSS_2048);
	if (error != CC_OK)
		return CRYPTO_ERR_SIGNATURE;

	/* Signature verification success */
	return CRYPTO_SUCCESS;
}

/*
 * Match a hash
 *
 * Digest info is passed in DER format following the ASN.1 structure detailed
 * above.
 */
static int verify_hash(void *data_ptr, unsigned int data_len,
		       void *digest_info_ptr, unsigned int digest_info_len)
{
	mbedtls_asn1_buf hash_oid, params;
	mbedtls_md_type_t md_alg;
	uint8_t *p, *end, *hash;
	CCHashResult_t pubKeyHash;
	size_t len;
	int rc;
	CCError_t error;

	/* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
	p = digest_info_ptr;
	end = p + digest_info_len;
	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
				  MBEDTLS_ASN1_SEQUENCE);
	if (rc != 0)
		return CRYPTO_ERR_HASH;

	/* Get the hash algorithm */
	rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
	if (rc != 0)
		return CRYPTO_ERR_HASH;

	rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
	if (rc != 0)
		return CRYPTO_ERR_HASH;
	/* Verify that hash algorithm is SHA256 */
	if (md_alg != MBEDTLS_MD_SHA256)
		return CRYPTO_ERR_HASH;

	/* Hash should be octet string type */
	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
	if (rc != 0)
		return CRYPTO_ERR_HASH;

	/* Length of hash must match the algorithm's size */
	if (len != HASH_RESULT_SIZE_IN_BYTES)
		return CRYPTO_ERR_HASH;

	/*
	 * CryptoCell utilises DMA internally to transfer data. Flush the data
	 * from caches.
	 */
	flush_dcache_range((uintptr_t)data_ptr, data_len);

	hash = p;
	error = SBROM_CryptoHash((uintptr_t)PLAT_CRYPTOCELL_BASE,
			(uintptr_t)data_ptr, data_len, pubKeyHash);
	if (error != CC_OK)
		return CRYPTO_ERR_HASH;

	rc = memcmp(pubKeyHash, hash, HASH_RESULT_SIZE_IN_BYTES);
	if (rc != 0)
		return CRYPTO_ERR_HASH;

	return CRYPTO_SUCCESS;
}

/*
 * Register crypto library descriptor
 */
REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash);