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