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