1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) Foundries Ltd. 2020 - All Rights Reserved
4  * Author: Jorge Ramirez <jorge@foundries.io>
5  */
6 
7 #include <crypto/crypto.h>
8 #include <se050.h>
9 #include <se050_utils.h>
10 #include <string.h>
11 #include <util.h>
12 
13 /* exp: minimal amount of transient memory required to generate an RSA key */
14 #define TRANSIENT_MEMORY_THRESHOLD	0x140
15 
16 #define NBR_OID			((uint32_t)(OID_MAX - OID_MIN))
17 #define IS_WATERMARKED(x)	(((x) & WATERMARKED(0)) == WATERMARKED(0))
18 
delete_transient_objects(void)19 static void delete_transient_objects(void)
20 {
21 	SE05x_AttestationType_t att = kSE05x_AttestationType_None;
22 	SE05x_SecureObjectType_t type = kSE05x_SecObjTyp_HMAC_KEY;
23 	uint8_t more = kSE05x_MoreIndicator_NA;
24 	smStatus_t status  = SM_NOT_OK;
25 	Se05xSession_t *ctx = NULL;
26 	uint8_t *list = NULL;
27 	size_t len = 1024;
28 	uint16_t offset = 0;
29 	uint8_t mode = 0;
30 	uint32_t id = 0;
31 	size_t i = 0;
32 
33 	if (!se050_session)
34 		return;
35 
36 	ctx = &se050_session->s_ctx;
37 
38 	list = calloc(1, len);
39 	if (!list)
40 		return;
41 	do {
42 		status = Se05x_API_ReadIDList(ctx, offset, 0xFF, &more,
43 					      list, &len);
44 		if (status != SM_OK)
45 			break;
46 
47 		offset = len;
48 		for (i = 0; i < len; i += 4) {
49 			id = (list[i + 0] << (3 * 8)) |
50 			     (list[i + 1] << (2 * 8)) |
51 			     (list[i + 2] << (1 * 8)) |
52 			     (list[i + 3] << (0 * 8));
53 
54 			if (id >= OID_MAX || id == 0)
55 				continue;
56 
57 			status = Se05x_API_ReadType(ctx, id, &type, &mode, att);
58 			if (status != SM_OK)
59 				continue;
60 
61 			if (mode == kKeyObject_Mode_Transient)
62 				Se05x_API_DeleteSecureObject(ctx, id);
63 		}
64 	} while (more == kSE05x_MoreIndicator_MORE);
65 
66 	free(list);
67 }
68 
generate_oid(uint32_t * val)69 static sss_status_t generate_oid(uint32_t *val)
70 {
71 	uint32_t oid = OID_MIN;
72 	uint32_t random = 0;
73 	size_t i = 0;
74 
75 	for (i = 0; i < NBR_OID; i++) {
76 		if (crypto_rng_read(&random, sizeof(random)))
77 			return kStatus_SSS_Fail;
78 
79 		oid = OID_MIN + (random & OID_MAX);
80 		if (oid > OID_MAX)
81 			continue;
82 
83 		if (!se050_key_exists(oid, &se050_session->s_ctx)) {
84 			*val = oid;
85 			return kStatus_SSS_Success;
86 		}
87 	}
88 
89 	return kStatus_SSS_Fail;
90 }
91 
se050_get_oid(uint32_t * val)92 sss_status_t se050_get_oid(uint32_t *val)
93 {
94 	sss_status_t status = kStatus_SSS_Success;
95 	uint16_t mem_t = 0;
96 
97 	if (!val)
98 		return kStatus_SSS_Fail;
99 
100 	status = se050_get_free_memory(&se050_session->s_ctx, &mem_t,
101 				       kSE05x_MemoryType_TRANSIENT_DESELECT);
102 	if (status != kStatus_SSS_Success)
103 		return kStatus_SSS_Fail;
104 
105 	if (mem_t < TRANSIENT_MEMORY_THRESHOLD)
106 		delete_transient_objects();
107 
108 	return generate_oid(val);
109 }
110 
se050_key(uint64_t key)111 static uint32_t se050_key(uint64_t key)
112 {
113 	uint32_t oid = (uint32_t)key;
114 
115 	if (!IS_WATERMARKED(key))
116 		return 0;
117 
118 	/* oid > OID_MAX could have been created by an external client */
119 	if (oid < OID_MIN)
120 		return 0;
121 
122 	return oid;
123 }
124 
se050_rsa_keypair_from_nvm(struct rsa_keypair * key)125 uint32_t se050_rsa_keypair_from_nvm(struct rsa_keypair *key)
126 {
127 	uint64_t key_id = 0;
128 
129 	if (!key)
130 		return 0;
131 
132 	if (crypto_bignum_num_bytes(key->d) != sizeof(uint64_t))
133 		return 0;
134 
135 	crypto_bignum_bn2bin(key->d, (uint8_t *)&key_id);
136 
137 	return se050_key(key_id);
138 }
139 
se050_ecc_keypair_from_nvm(struct ecc_keypair * key)140 uint32_t se050_ecc_keypair_from_nvm(struct ecc_keypair *key)
141 {
142 	uint64_t key_id = 0;
143 
144 	if (!key)
145 		return 0;
146 
147 	if (crypto_bignum_num_bytes(key->d) != sizeof(uint64_t))
148 		return 0;
149 
150 	crypto_bignum_bn2bin(key->d, (uint8_t *)&key_id);
151 
152 	return se050_key(key_id);
153 }
154 
se050_generate_private_key(uint32_t oid)155 uint64_t se050_generate_private_key(uint32_t oid)
156 {
157 	return WATERMARKED(oid);
158 }
159 
se050_refcount_init_ctx(uint8_t ** cnt)160 void se050_refcount_init_ctx(uint8_t **cnt)
161 {
162 	if (!*cnt) {
163 		*cnt = calloc(1, sizeof(uint8_t));
164 		if (*cnt)
165 			**cnt = 1;
166 		else
167 			EMSG("can't allocate refcount");
168 	} else {
169 		**cnt = **cnt + 1;
170 	}
171 }
172 
se050_refcount_final_ctx(uint8_t * cnt)173 int se050_refcount_final_ctx(uint8_t *cnt)
174 {
175 	if (!cnt)
176 		return 1;
177 
178 	if (!*cnt) {
179 		free(cnt);
180 		return 1;
181 	}
182 
183 	*cnt = *cnt - 1;
184 
185 	return 0;
186 }
187