1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2017-2020, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <compiler.h> 8 #include <pkcs11_ta.h> 9 #include <stddef.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <string_ext.h> 13 #include <tee_internal_api.h> 14 #include <tee_internal_api_extensions.h> 15 #include <trace.h> 16 #include <util.h> 17 18 #include "attributes.h" 19 #include "pkcs11_helpers.h" 20 #include "serializer.h" 21 22 enum pkcs11_rc init_attributes_head(struct obj_attrs **head) 23 { 24 *head = TEE_Malloc(sizeof(**head), TEE_MALLOC_FILL_ZERO); 25 if (!*head) 26 return PKCS11_CKR_DEVICE_MEMORY; 27 28 return PKCS11_CKR_OK; 29 } 30 31 enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute, 32 void *data, size_t size) 33 { 34 size_t buf_len = sizeof(struct obj_attrs) + (*head)->attrs_size; 35 char **bstart = (void *)head; 36 enum pkcs11_rc rc = PKCS11_CKR_OK; 37 uint32_t data32 = 0; 38 39 data32 = attribute; 40 rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t)); 41 if (rc) 42 return rc; 43 44 data32 = size; 45 rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t)); 46 if (rc) 47 return rc; 48 49 rc = serialize(bstart, &buf_len, data, size); 50 if (rc) 51 return rc; 52 53 /* Alloced buffer is always well aligned */ 54 head = (void *)bstart; 55 (*head)->attrs_size += 2 * sizeof(uint32_t) + size; 56 (*head)->attrs_count++; 57 58 return rc; 59 } 60 61 static enum pkcs11_rc _remove_attribute(struct obj_attrs **head, 62 uint32_t attribute, bool empty) 63 { 64 struct obj_attrs *h = *head; 65 char *cur = NULL; 66 char *end = NULL; 67 size_t next_off = 0; 68 69 /* Let's find the target attribute */ 70 cur = (char *)h + sizeof(struct obj_attrs); 71 end = cur + h->attrs_size; 72 for (; cur < end; cur += next_off) { 73 struct pkcs11_attribute_head pkcs11_ref = { }; 74 75 TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref)); 76 next_off = sizeof(pkcs11_ref) + pkcs11_ref.size; 77 78 if (pkcs11_ref.id != attribute) 79 continue; 80 81 if (empty && pkcs11_ref.size) 82 return PKCS11_CKR_FUNCTION_FAILED; 83 84 TEE_MemMove(cur, cur + next_off, end - (cur + next_off)); 85 86 h->attrs_count--; 87 h->attrs_size -= next_off; 88 end -= next_off; 89 next_off = 0; 90 91 return PKCS11_CKR_OK; 92 } 93 94 DMSG("Attribute %s (%#x) not found", id2str_attr(attribute), attribute); 95 return PKCS11_RV_NOT_FOUND; 96 } 97 98 enum pkcs11_rc remove_empty_attribute(struct obj_attrs **head, 99 uint32_t attribute) 100 { 101 return _remove_attribute(head, attribute, true /* empty */); 102 } 103 104 void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute, 105 void **attr, uint32_t *attr_size, size_t *count) 106 { 107 char *cur = (char *)head + sizeof(struct obj_attrs); 108 char *end = cur + head->attrs_size; 109 size_t next_off = 0; 110 size_t max_found = *count; 111 size_t found = 0; 112 void **attr_ptr = attr; 113 uint32_t *attr_size_ptr = attr_size; 114 115 for (; cur < end; cur += next_off) { 116 /* Structure aligned copy of the pkcs11_ref in the object */ 117 struct pkcs11_attribute_head pkcs11_ref = { }; 118 119 TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref)); 120 next_off = sizeof(pkcs11_ref) + pkcs11_ref.size; 121 122 if (pkcs11_ref.id != attribute) 123 continue; 124 125 found++; 126 127 if (!max_found) 128 continue; /* only count matching attributes */ 129 130 if (attr) { 131 if (pkcs11_ref.size) 132 *attr_ptr++ = cur + sizeof(pkcs11_ref); 133 else 134 *attr_ptr++ = NULL; 135 } 136 137 if (attr_size) 138 *attr_size_ptr++ = pkcs11_ref.size; 139 140 if (found == max_found) 141 break; 142 } 143 144 /* Sanity */ 145 if (cur > end) { 146 DMSG("Exceeding serial object length"); 147 TEE_Panic(0); 148 } 149 150 *count = found; 151 } 152 153 enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute, 154 void **attr_ptr, uint32_t *attr_size) 155 { 156 size_t count = 1; 157 158 get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count); 159 160 if (!count) 161 return PKCS11_RV_NOT_FOUND; 162 163 if (count != 1) 164 return PKCS11_CKR_GENERAL_ERROR; 165 166 return PKCS11_CKR_OK; 167 } 168 169 enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute, 170 void *attr, uint32_t *attr_size) 171 { 172 enum pkcs11_rc rc = PKCS11_CKR_OK; 173 void *attr_ptr = NULL; 174 uint32_t size = 0; 175 176 rc = get_attribute_ptr(head, attribute, &attr_ptr, &size); 177 if (rc) 178 return rc; 179 180 if (attr_size && *attr_size < size) { 181 *attr_size = size; 182 /* This reuses buffer-to-small for any bad size matching */ 183 return PKCS11_CKR_BUFFER_TOO_SMALL; 184 } 185 186 if (attr) 187 TEE_MemMove(attr, attr_ptr, size); 188 189 if (attr_size) 190 *attr_size = size; 191 192 return PKCS11_CKR_OK; 193 } 194 195 enum pkcs11_rc set_attribute(struct obj_attrs **head, uint32_t attribute, 196 void *data, size_t size) 197 { 198 enum pkcs11_rc rc = PKCS11_CKR_OK; 199 200 rc = _remove_attribute(head, attribute, false); 201 if (rc != PKCS11_CKR_OK && rc != PKCS11_RV_NOT_FOUND) 202 return rc; 203 204 return add_attribute(head, attribute, data, size); 205 } 206 207 enum pkcs11_rc modify_attributes_list(struct obj_attrs **dst, 208 struct obj_attrs *head) 209 { 210 char *cur = (char *)head + sizeof(struct obj_attrs); 211 char *end = cur + head->attrs_size; 212 size_t len = 0; 213 enum pkcs11_rc rc = PKCS11_CKR_OK; 214 215 for (; cur < end; cur += len) { 216 struct pkcs11_attribute_head *cli_ref = (void *)cur; 217 /* Structure aligned copy of the pkcs11_ref in the object */ 218 struct pkcs11_attribute_head cli_head = { }; 219 220 TEE_MemMove(&cli_head, cur, sizeof(cli_head)); 221 len = sizeof(cli_head) + cli_head.size; 222 223 rc = set_attribute(dst, cli_head.id, 224 cli_head.size ? cli_ref->data : NULL, 225 cli_head.size); 226 if (rc) 227 return rc; 228 } 229 230 return PKCS11_CKR_OK; 231 } 232 233 bool get_bool(struct obj_attrs *head, uint32_t attribute) 234 { 235 enum pkcs11_rc rc = PKCS11_CKR_OK; 236 uint8_t bbool = 0; 237 uint32_t size = sizeof(bbool); 238 239 rc = get_attribute(head, attribute, &bbool, &size); 240 241 if (rc == PKCS11_RV_NOT_FOUND) 242 return false; 243 244 assert(rc == PKCS11_CKR_OK); 245 return bbool; 246 } 247 248 bool attributes_match_reference(struct obj_attrs *candidate, 249 struct obj_attrs *ref) 250 { 251 size_t count = ref->attrs_count; 252 unsigned char *ref_attr = ref->attrs; 253 uint32_t rc = PKCS11_CKR_GENERAL_ERROR; 254 255 if (!ref->attrs_count) { 256 DMSG("Empty reference match all"); 257 return true; 258 } 259 260 for (count = 0; count < ref->attrs_count; count++) { 261 struct pkcs11_attribute_head pkcs11_ref = { }; 262 void *value = NULL; 263 uint32_t size = 0; 264 265 TEE_MemMove(&pkcs11_ref, ref_attr, sizeof(pkcs11_ref)); 266 267 /* Hidden attributes cannot be matched */ 268 if (attribute_is_hidden(&pkcs11_ref)) 269 return false; 270 271 rc = get_attribute_ptr(candidate, pkcs11_ref.id, &value, &size); 272 273 if (rc || !value || size != pkcs11_ref.size || 274 TEE_MemCompare(ref_attr + sizeof(pkcs11_ref), value, size)) 275 return false; 276 277 ref_attr += sizeof(pkcs11_ref) + pkcs11_ref.size; 278 } 279 280 return true; 281 } 282 283 enum pkcs11_rc attributes_match_add_reference(struct obj_attrs **head, 284 struct obj_attrs *ref) 285 { 286 size_t count = ref->attrs_count; 287 unsigned char *ref_attr = ref->attrs; 288 enum pkcs11_rc rc = PKCS11_CKR_OK; 289 290 if (!ref->attrs_count) 291 return PKCS11_CKR_OK; 292 293 for (count = 0; count < ref->attrs_count; count++) { 294 struct pkcs11_attribute_head pkcs11_ref = { }; 295 void *value = NULL; 296 uint32_t size = 0; 297 298 TEE_MemMove(&pkcs11_ref, ref_attr, sizeof(pkcs11_ref)); 299 300 rc = get_attribute_ptr(*head, pkcs11_ref.id, &value, &size); 301 if (rc == PKCS11_RV_NOT_FOUND) { 302 rc = add_attribute(head, pkcs11_ref.id, 303 ref_attr + sizeof(pkcs11_ref), 304 pkcs11_ref.size); 305 if (rc) 306 return rc; 307 } else { 308 if (rc || !value || size != pkcs11_ref.size || 309 TEE_MemCompare(ref_attr + sizeof(pkcs11_ref), value, 310 size)) 311 return PKCS11_CKR_TEMPLATE_INCONSISTENT; 312 } 313 314 ref_attr += sizeof(pkcs11_ref) + pkcs11_ref.size; 315 } 316 317 return PKCS11_CKR_OK; 318 } 319 320 #if CFG_TEE_TA_LOG_LEVEL > 0 321 /* 322 * Debug: dump CK attribute array to output trace 323 */ 324 #define ATTR_TRACE_FMT "%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte" 325 #define ATTR_FMT_0BYTE ATTR_TRACE_FMT ")" 326 #define ATTR_FMT_1BYTE ATTR_TRACE_FMT ": %02x)" 327 #define ATTR_FMT_2BYTE ATTR_TRACE_FMT ": %02x %02x)" 328 #define ATTR_FMT_3BYTE ATTR_TRACE_FMT ": %02x %02x %02x)" 329 #define ATTR_FMT_4BYTE ATTR_TRACE_FMT ": %02x %02x %02x %02x)" 330 #define ATTR_FMT_ARRAY ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)" 331 332 static void __trace_attributes(char *prefix, void *src, void *end) 333 { 334 size_t next_off = 0; 335 char *prefix2 = NULL; 336 size_t prefix_len = strlen(prefix); 337 char *cur = src; 338 339 /* append 4 spaces to the prefix plus terminal '\0' */ 340 prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO); 341 if (!prefix2) 342 return; 343 344 TEE_MemMove(prefix2, prefix, prefix_len + 1); 345 TEE_MemFill(prefix2 + prefix_len, ' ', 4); 346 *(prefix2 + prefix_len + 4) = '\0'; 347 348 for (; cur < (char *)end; cur += next_off) { 349 struct pkcs11_attribute_head pkcs11_ref = { }; 350 uint8_t data[4] = { 0 }; 351 352 TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref)); 353 TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref), 354 MIN(pkcs11_ref.size, sizeof(data))); 355 356 next_off = sizeof(pkcs11_ref) + pkcs11_ref.size; 357 358 switch (pkcs11_ref.size) { 359 case 0: 360 IMSG_RAW(ATTR_FMT_0BYTE, 361 prefix, id2str_attr(pkcs11_ref.id), "*", 362 pkcs11_ref.id, pkcs11_ref.size); 363 break; 364 case 1: 365 IMSG_RAW(ATTR_FMT_1BYTE, 366 prefix, id2str_attr(pkcs11_ref.id), 367 id2str_attr_value(pkcs11_ref.id, 368 pkcs11_ref.size, 369 cur + sizeof(pkcs11_ref)), 370 pkcs11_ref.id, pkcs11_ref.size, data[0]); 371 break; 372 case 2: 373 IMSG_RAW(ATTR_FMT_2BYTE, 374 prefix, id2str_attr(pkcs11_ref.id), 375 id2str_attr_value(pkcs11_ref.id, 376 pkcs11_ref.size, 377 cur + sizeof(pkcs11_ref)), 378 pkcs11_ref.id, pkcs11_ref.size, data[0], 379 data[1]); 380 break; 381 case 3: 382 IMSG_RAW(ATTR_FMT_3BYTE, 383 prefix, id2str_attr(pkcs11_ref.id), 384 id2str_attr_value(pkcs11_ref.id, 385 pkcs11_ref.size, 386 cur + sizeof(pkcs11_ref)), 387 pkcs11_ref.id, pkcs11_ref.size, 388 data[0], data[1], data[2]); 389 break; 390 case 4: 391 IMSG_RAW(ATTR_FMT_4BYTE, 392 prefix, id2str_attr(pkcs11_ref.id), 393 id2str_attr_value(pkcs11_ref.id, 394 pkcs11_ref.size, 395 cur + sizeof(pkcs11_ref)), 396 pkcs11_ref.id, pkcs11_ref.size, 397 data[0], data[1], data[2], data[3]); 398 break; 399 default: 400 IMSG_RAW(ATTR_FMT_ARRAY, 401 prefix, id2str_attr(pkcs11_ref.id), 402 id2str_attr_value(pkcs11_ref.id, 403 pkcs11_ref.size, 404 cur + sizeof(pkcs11_ref)), 405 pkcs11_ref.id, pkcs11_ref.size, 406 data[0], data[1], data[2], data[3]); 407 break; 408 } 409 410 switch (pkcs11_ref.id) { 411 case PKCS11_CKA_WRAP_TEMPLATE: 412 case PKCS11_CKA_UNWRAP_TEMPLATE: 413 case PKCS11_CKA_DERIVE_TEMPLATE: 414 if (pkcs11_ref.size) 415 trace_attributes(prefix2, 416 cur + sizeof(pkcs11_ref)); 417 break; 418 default: 419 break; 420 } 421 } 422 423 /* Sanity */ 424 if (cur != end) 425 EMSG("Warning: unexpected alignment in object attributes"); 426 427 TEE_Free(prefix2); 428 } 429 430 void trace_attributes(const char *prefix, void *ref) 431 { 432 struct obj_attrs head = { }; 433 char *pre = NULL; 434 435 TEE_MemMove(&head, ref, sizeof(head)); 436 437 if (!head.attrs_count) 438 return; 439 440 pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO); 441 if (!pre) { 442 EMSG("%s: out of memory", prefix); 443 return; 444 } 445 446 if (prefix) 447 TEE_MemMove(pre, prefix, strlen(prefix)); 448 449 IMSG_RAW("%s,--- (serial object) Attributes list --------", pre); 450 IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes", 451 pre, head.attrs_count, head.attrs_size); 452 453 pre[prefix ? strlen(prefix) : 0] = '|'; 454 __trace_attributes(pre, (char *)ref + sizeof(head), 455 (char *)ref + sizeof(head) + head.attrs_size); 456 457 IMSG_RAW("%s`-----------------------", prefix ? prefix : ""); 458 459 TEE_Free(pre); 460 } 461 #endif /*CFG_TEE_TA_LOG_LEVEL*/ 462