1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <string.h>
7 
8 #include <zephyr/init.h>
9 #include <zephyr/kernel.h>
10 
11 #include "tls_internal.h"
12 #include "tls_credentials_digest_raw.h"
13 
14 #include <zephyr/logging/log.h>
15 
16 LOG_MODULE_DECLARE(tls_credentials,
17 		   CONFIG_TLS_CREDENTIALS_LOG_LEVEL);
18 
19 /* Global pool of credentials shared among TLS contexts. */
20 static struct tls_credential credentials[CONFIG_TLS_MAX_CREDENTIALS_NUMBER];
21 
22 /* A mutex for protecting access to the credentials array. */
23 static struct k_mutex credential_lock;
24 
credentials_init(void)25 static int credentials_init(void)
26 {
27 	(void)memset(credentials, 0, sizeof(credentials));
28 
29 	k_mutex_init(&credential_lock);
30 
31 	return 0;
32 }
33 SYS_INIT(credentials_init, POST_KERNEL, 0);
34 
unused_credential_get(void)35 static struct tls_credential *unused_credential_get(void)
36 {
37 	int i;
38 
39 	for (i = 0; i < ARRAY_SIZE(credentials); i++) {
40 		if (credentials[i].type == TLS_CREDENTIAL_NONE) {
41 			return &credentials[i];
42 		}
43 	}
44 
45 	return NULL;
46 }
47 
credential_get(sec_tag_t tag,enum tls_credential_type type)48 struct tls_credential *credential_get(sec_tag_t tag,
49 				      enum tls_credential_type type)
50 {
51 	int i;
52 
53 	for (i = 0; i < ARRAY_SIZE(credentials); i++) {
54 		if (credentials[i].type == type && credentials[i].tag == tag) {
55 			return &credentials[i];
56 		}
57 	}
58 
59 	return NULL;
60 }
61 
credential_next_get(sec_tag_t tag,struct tls_credential * iter)62 struct tls_credential *credential_next_get(sec_tag_t tag,
63 					   struct tls_credential *iter)
64 {
65 	int i;
66 
67 	if (!iter) {
68 		iter = credentials;
69 	} else {
70 		iter++;
71 	}
72 
73 	for (i = iter - credentials; i < ARRAY_SIZE(credentials); i++) {
74 		if (credentials[i].type != TLS_CREDENTIAL_NONE &&
75 		    credentials[i].tag == tag) {
76 			return &credentials[i];
77 		}
78 	}
79 
80 	return NULL;
81 }
82 
credential_next_tag_get(sec_tag_t iter)83 sec_tag_t credential_next_tag_get(sec_tag_t iter)
84 {
85 	int i;
86 	sec_tag_t lowest = TLS_SEC_TAG_NONE;
87 
88 	/* Scan all slots and find lowest sectag greater than iter */
89 	for (i = 0; i < ARRAY_SIZE(credentials); i++) {
90 		/* Skip empty slots. */
91 		if (credentials[i].type == TLS_CREDENTIAL_NONE) {
92 			continue;
93 		}
94 
95 		/* Skip any slots containing sectags not greater than iter */
96 		if (credentials[i].tag <= iter && iter != TLS_SEC_TAG_NONE) {
97 			continue;
98 		}
99 
100 		/* Find the lowest of such slots */
101 		if (lowest == TLS_SEC_TAG_NONE || credentials[i].tag < lowest) {
102 			lowest = credentials[i].tag;
103 		}
104 	}
105 
106 	return lowest;
107 }
108 
credential_digest(struct tls_credential * credential,void * dest,size_t * len)109 int credential_digest(struct tls_credential *credential, void *dest, size_t *len)
110 {
111 	return credential_digest_raw(credential, dest, len);
112 }
113 
credentials_lock(void)114 void credentials_lock(void)
115 {
116 	k_mutex_lock(&credential_lock, K_FOREVER);
117 }
118 
credentials_unlock(void)119 void credentials_unlock(void)
120 {
121 	k_mutex_unlock(&credential_lock);
122 }
123 
tls_credential_add(sec_tag_t tag,enum tls_credential_type type,const void * cred,size_t credlen)124 int tls_credential_add(sec_tag_t tag, enum tls_credential_type type,
125 		       const void *cred, size_t credlen)
126 {
127 	struct tls_credential *credential;
128 	int ret = 0;
129 
130 	credentials_lock();
131 
132 	credential = credential_get(tag, type);
133 	if (credential != NULL) {
134 		ret = -EEXIST;
135 		goto exit;
136 	}
137 
138 	credential = unused_credential_get();
139 	if (credential == NULL) {
140 		ret = -ENOMEM;
141 		goto exit;
142 	}
143 
144 	credential->tag = tag;
145 	credential->type = type;
146 	credential->buf = cred;
147 	credential->len = credlen;
148 
149 exit:
150 	credentials_unlock();
151 
152 	return ret;
153 }
154 
tls_credential_get(sec_tag_t tag,enum tls_credential_type type,void * cred,size_t * credlen)155 int tls_credential_get(sec_tag_t tag, enum tls_credential_type type,
156 		       void *cred, size_t *credlen)
157 {
158 	struct tls_credential *credential;
159 	int ret = 0;
160 
161 	credentials_lock();
162 
163 	credential = credential_get(tag, type);
164 	if (credential == NULL) {
165 		ret = -ENOENT;
166 		*credlen = 0;
167 		goto exit;
168 	}
169 
170 	if (credential->len > *credlen) {
171 		ret = -EFBIG;
172 		LOG_DBG("Not enough room in the credential buffer to "
173 			"retrieve credential with sectag %d and type %d. "
174 			"Increase TLS_CREDENTIALS_SHELL_MAX_CRED_LEN "
175 			">= %d.\n",
176 			tag, (int)type, (int)credential->len);
177 		*credlen = credential->len;
178 		goto exit;
179 	}
180 
181 	*credlen = credential->len;
182 	memcpy(cred, credential->buf, credential->len);
183 
184 exit:
185 	credentials_unlock();
186 
187 	return ret;
188 }
189 
tls_credential_delete(sec_tag_t tag,enum tls_credential_type type)190 int tls_credential_delete(sec_tag_t tag, enum tls_credential_type type)
191 {
192 	struct tls_credential *credential;
193 	int ret = 0;
194 
195 	credentials_lock();
196 
197 	credential = credential_get(tag, type);
198 
199 	if (!credential) {
200 		ret = -ENOENT;
201 		goto exit;
202 	}
203 
204 	(void)memset(credential, 0, sizeof(struct tls_credential));
205 	credential->type = TLS_CREDENTIAL_NONE;
206 
207 exit:
208 	credentials_unlock();
209 
210 	return ret;
211 }
212