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 void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute, 62 void **attr, uint32_t *attr_size, size_t *count) 63 { 64 char *cur = (char *)head + sizeof(struct obj_attrs); 65 char *end = cur + head->attrs_size; 66 size_t next_off = 0; 67 size_t max_found = *count; 68 size_t found = 0; 69 void **attr_ptr = attr; 70 uint32_t *attr_size_ptr = attr_size; 71 72 for (; cur < end; cur += next_off) { 73 /* Structure aligned copy of the pkcs11_ref in the object */ 74 struct pkcs11_attribute_head pkcs11_ref = { }; 75 76 TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref)); 77 next_off = sizeof(pkcs11_ref) + pkcs11_ref.size; 78 79 if (pkcs11_ref.id != attribute) 80 continue; 81 82 found++; 83 84 if (!max_found) 85 continue; /* only count matching attributes */ 86 87 if (attr) { 88 if (pkcs11_ref.size) 89 *attr_ptr++ = cur + sizeof(pkcs11_ref); 90 else 91 *attr_ptr++ = NULL; 92 } 93 94 if (attr_size) 95 *attr_size_ptr++ = pkcs11_ref.size; 96 97 if (found == max_found) 98 break; 99 } 100 101 /* Sanity */ 102 if (cur > end) { 103 DMSG("Exceeding serial object length"); 104 TEE_Panic(0); 105 } 106 107 *count = found; 108 } 109 110 enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute, 111 void **attr_ptr, uint32_t *attr_size) 112 { 113 size_t count = 1; 114 115 get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count); 116 117 if (!count) 118 return PKCS11_RV_NOT_FOUND; 119 120 if (count != 1) 121 return PKCS11_CKR_GENERAL_ERROR; 122 123 return PKCS11_CKR_OK; 124 } 125 126 enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute, 127 void *attr, uint32_t *attr_size) 128 { 129 enum pkcs11_rc rc = PKCS11_CKR_OK; 130 void *attr_ptr = NULL; 131 uint32_t size = 0; 132 133 rc = get_attribute_ptr(head, attribute, &attr_ptr, &size); 134 if (rc) 135 return rc; 136 137 if (attr_size && *attr_size != size) { 138 *attr_size = size; 139 /* This reuses buffer-to-small for any bad size matching */ 140 return PKCS11_CKR_BUFFER_TOO_SMALL; 141 } 142 143 if (attr) 144 TEE_MemMove(attr, attr_ptr, size); 145 146 if (attr_size) 147 *attr_size = size; 148 149 return PKCS11_CKR_OK; 150 } 151 152 bool get_bool(struct obj_attrs *head, uint32_t attribute) 153 { 154 enum pkcs11_rc rc = PKCS11_CKR_OK; 155 uint8_t bbool = 0; 156 uint32_t size = sizeof(bbool); 157 158 rc = get_attribute(head, attribute, &bbool, &size); 159 160 if (rc == PKCS11_RV_NOT_FOUND) 161 return false; 162 163 assert(rc == PKCS11_CKR_OK); 164 return bbool; 165 } 166 167 #if CFG_TEE_TA_LOG_LEVEL > 0 168 /* 169 * Debug: dump CK attribute array to output trace 170 */ 171 #define ATTR_TRACE_FMT "%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte" 172 #define ATTR_FMT_0BYTE ATTR_TRACE_FMT ")" 173 #define ATTR_FMT_1BYTE ATTR_TRACE_FMT ": %02x)" 174 #define ATTR_FMT_2BYTE ATTR_TRACE_FMT ": %02x %02x)" 175 #define ATTR_FMT_3BYTE ATTR_TRACE_FMT ": %02x %02x %02x)" 176 #define ATTR_FMT_4BYTE ATTR_TRACE_FMT ": %02x %02x %02x %02x)" 177 #define ATTR_FMT_ARRAY ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)" 178 179 static void __trace_attributes(char *prefix, void *src, void *end) 180 { 181 size_t next_off = 0; 182 char *prefix2 = NULL; 183 size_t prefix_len = strlen(prefix); 184 char *cur = src; 185 186 /* append 4 spaces to the prefix plus terminal '\0' */ 187 prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO); 188 if (!prefix2) 189 return; 190 191 TEE_MemMove(prefix2, prefix, prefix_len + 1); 192 TEE_MemFill(prefix2 + prefix_len, ' ', 4); 193 *(prefix2 + prefix_len + 4) = '\0'; 194 195 for (; cur < (char *)end; cur += next_off) { 196 struct pkcs11_attribute_head pkcs11_ref = { }; 197 uint8_t data[4] = { 0 }; 198 199 TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref)); 200 TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref), 201 MIN(pkcs11_ref.size, sizeof(data))); 202 203 next_off = sizeof(pkcs11_ref) + pkcs11_ref.size; 204 205 switch (pkcs11_ref.size) { 206 case 0: 207 IMSG_RAW(ATTR_FMT_0BYTE, 208 prefix, id2str_attr(pkcs11_ref.id), "*", 209 pkcs11_ref.id, pkcs11_ref.size); 210 break; 211 case 1: 212 IMSG_RAW(ATTR_FMT_1BYTE, 213 prefix, id2str_attr(pkcs11_ref.id), 214 id2str_attr_value(pkcs11_ref.id, 215 pkcs11_ref.size, 216 cur + sizeof(pkcs11_ref)), 217 pkcs11_ref.id, pkcs11_ref.size, data[0]); 218 break; 219 case 2: 220 IMSG_RAW(ATTR_FMT_2BYTE, 221 prefix, id2str_attr(pkcs11_ref.id), 222 id2str_attr_value(pkcs11_ref.id, 223 pkcs11_ref.size, 224 cur + sizeof(pkcs11_ref)), 225 pkcs11_ref.id, pkcs11_ref.size, data[0], 226 data[1]); 227 break; 228 case 3: 229 IMSG_RAW(ATTR_FMT_3BYTE, 230 prefix, id2str_attr(pkcs11_ref.id), 231 id2str_attr_value(pkcs11_ref.id, 232 pkcs11_ref.size, 233 cur + sizeof(pkcs11_ref)), 234 pkcs11_ref.id, pkcs11_ref.size, 235 data[0], data[1], data[2]); 236 break; 237 case 4: 238 IMSG_RAW(ATTR_FMT_4BYTE, 239 prefix, id2str_attr(pkcs11_ref.id), 240 id2str_attr_value(pkcs11_ref.id, 241 pkcs11_ref.size, 242 cur + sizeof(pkcs11_ref)), 243 pkcs11_ref.id, pkcs11_ref.size, 244 data[0], data[1], data[2], data[3]); 245 break; 246 default: 247 IMSG_RAW(ATTR_FMT_ARRAY, 248 prefix, id2str_attr(pkcs11_ref.id), 249 id2str_attr_value(pkcs11_ref.id, 250 pkcs11_ref.size, 251 cur + sizeof(pkcs11_ref)), 252 pkcs11_ref.id, pkcs11_ref.size, 253 data[0], data[1], data[2], data[3]); 254 break; 255 } 256 257 switch (pkcs11_ref.id) { 258 case PKCS11_CKA_WRAP_TEMPLATE: 259 case PKCS11_CKA_UNWRAP_TEMPLATE: 260 case PKCS11_CKA_DERIVE_TEMPLATE: 261 if (pkcs11_ref.size) 262 trace_attributes(prefix2, 263 cur + sizeof(pkcs11_ref)); 264 break; 265 default: 266 break; 267 } 268 } 269 270 /* Sanity */ 271 if (cur != end) 272 EMSG("Warning: unexpected alignment in object attributes"); 273 274 TEE_Free(prefix2); 275 } 276 277 void trace_attributes(const char *prefix, void *ref) 278 { 279 struct obj_attrs head = { }; 280 char *pre = NULL; 281 282 TEE_MemMove(&head, ref, sizeof(head)); 283 284 if (!head.attrs_count) 285 return; 286 287 pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO); 288 if (!pre) { 289 EMSG("%s: out of memory", prefix); 290 return; 291 } 292 293 if (prefix) 294 TEE_MemMove(pre, prefix, strlen(prefix)); 295 296 IMSG_RAW("%s,--- (serial object) Attributes list --------", pre); 297 IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes", 298 pre, head.attrs_count, head.attrs_size); 299 300 pre[prefix ? strlen(prefix) : 0] = '|'; 301 __trace_attributes(pre, (char *)ref + sizeof(head), 302 (char *)ref + sizeof(head) + head.attrs_size); 303 304 IMSG_RAW("%s`-----------------------", prefix ? prefix : ""); 305 306 TEE_Free(pre); 307 } 308 #endif /*CFG_TEE_TA_LOG_LEVEL*/ 309