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