lgutil.c (10600B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 #include "lgdb.h" 5 #include "secerr.h" 6 #include "lgglue.h" 7 8 /* 9 * ******************** Attribute Utilities ******************************* 10 */ 11 12 /* 13 * look up and attribute structure from a type and Object structure. 14 * The returned attribute is referenced and needs to be freed when 15 * it is no longer needed. 16 */ 17 const CK_ATTRIBUTE * 18 lg_FindAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, 19 CK_ULONG count) 20 { 21 unsigned int i; 22 23 for (i = 0; i < count; i++) { 24 if (templ[i].type == type) { 25 return &templ[i]; 26 } 27 } 28 return NULL; 29 } 30 31 /* 32 * return true if object has attribute 33 */ 34 PRBool 35 lg_hasAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, 36 CK_ULONG count) 37 { 38 if (lg_FindAttribute(type, templ, count) == NULL) { 39 return PR_FALSE; 40 } 41 return PR_TRUE; 42 } 43 44 /* 45 * copy an attribute into a SECItem. Secitem is allocated in the specified 46 * arena. 47 */ 48 CK_RV 49 lg_Attribute2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 50 const CK_ATTRIBUTE *templ, CK_ULONG count, 51 SECItem *item) 52 { 53 int len; 54 const CK_ATTRIBUTE *attribute; 55 56 attribute = lg_FindAttribute(type, templ, count); 57 if (attribute == NULL) 58 return CKR_TEMPLATE_INCOMPLETE; 59 len = attribute->ulValueLen; 60 61 if (arena) { 62 item->data = (unsigned char *)PORT_ArenaAlloc(arena, len); 63 } else { 64 item->data = (unsigned char *)PORT_Alloc(len); 65 } 66 if (item->data == NULL) { 67 return CKR_HOST_MEMORY; 68 } 69 item->len = len; 70 if (item->len) { 71 PORT_Memcpy(item->data, attribute->pValue, len); 72 } 73 return CKR_OK; 74 } 75 76 /* 77 * copy an unsigned attribute into a SECItem. Secitem is allocated in 78 * the specified arena. 79 */ 80 CK_RV 81 lg_Attribute2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 82 const CK_ATTRIBUTE *templ, CK_ULONG count, 83 SECItem *item) 84 { 85 const CK_ATTRIBUTE *attribute; 86 item->data = NULL; 87 88 attribute = lg_FindAttribute(type, templ, count); 89 if (attribute == NULL) 90 return CKR_TEMPLATE_INCOMPLETE; 91 92 (void)SECITEM_AllocItem(arena, item, attribute->ulValueLen); 93 if (item->data == NULL) { 94 return CKR_HOST_MEMORY; 95 } 96 PORT_Memcpy(item->data, attribute->pValue, item->len); 97 return CKR_OK; 98 } 99 100 /* 101 * copy an unsigned attribute into a SECItem. Secitem is allocated in 102 * the specified arena. 103 */ 104 CK_RV 105 lg_PrivAttr2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 106 const CK_ATTRIBUTE *templ, CK_ULONG count, 107 SECItem *item, SDB *sdbpw) 108 { 109 const CK_ATTRIBUTE *attribute; 110 SECItem epki, *dest = NULL; 111 SECStatus rv; 112 113 item->data = NULL; 114 115 attribute = lg_FindAttribute(type, templ, count); 116 if (attribute == NULL) 117 return CKR_TEMPLATE_INCOMPLETE; 118 119 epki.data = attribute->pValue; 120 epki.len = attribute->ulValueLen; 121 122 rv = lg_util_decrypt(sdbpw, &epki, &dest); 123 if (rv != SECSuccess) { 124 return CKR_USER_NOT_LOGGED_IN; 125 } 126 (void)SECITEM_AllocItem(arena, item, dest->len); 127 if (item->data == NULL) { 128 SECITEM_FreeItem(dest, PR_TRUE); 129 return CKR_HOST_MEMORY; 130 } 131 132 PORT_Memcpy(item->data, dest->data, item->len); 133 SECITEM_FreeItem(dest, PR_TRUE); 134 return CKR_OK; 135 } 136 137 CK_RV 138 lg_PrivAttr2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 139 const CK_ATTRIBUTE *templ, CK_ULONG count, 140 SECItem *item, SDB *sdbpw) 141 { 142 return lg_PrivAttr2SSecItem(arena, type, templ, count, item, sdbpw); 143 } 144 145 /* 146 * this is only valid for CK_BBOOL type attributes. Return the state 147 * of that attribute. 148 */ 149 PRBool 150 lg_isTrue(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count) 151 { 152 const CK_ATTRIBUTE *attribute; 153 PRBool tok = PR_FALSE; 154 155 attribute = lg_FindAttribute(type, templ, count); 156 if (attribute == NULL) { 157 return PR_FALSE; 158 } 159 tok = (PRBool)(*(CK_BBOOL *)attribute->pValue); 160 161 return tok; 162 } 163 164 /* 165 * return a null terminated string from attribute 'type'. This string 166 * is allocated and needs to be freed with PORT_Free() When complete. 167 */ 168 char * 169 lg_getString(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count) 170 { 171 const CK_ATTRIBUTE *attribute; 172 char *label = NULL; 173 174 attribute = lg_FindAttribute(type, templ, count); 175 if (attribute == NULL) 176 return NULL; 177 178 if (attribute->pValue != NULL) { 179 label = (char *)PORT_Alloc(attribute->ulValueLen + 1); 180 if (label == NULL) { 181 return NULL; 182 } 183 184 PORT_Memcpy(label, attribute->pValue, attribute->ulValueLen); 185 label[attribute->ulValueLen] = 0; 186 } 187 return label; 188 } 189 190 CK_RV 191 lg_GetULongAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, 192 CK_ULONG count, CK_ULONG *longData) 193 { 194 const CK_ATTRIBUTE *attribute; 195 CK_ULONG value = 0; 196 const unsigned char *data; 197 int i; 198 199 attribute = lg_FindAttribute(type, templ, count); 200 if (attribute == NULL) 201 return CKR_TEMPLATE_INCOMPLETE; 202 203 if (attribute->ulValueLen != 4) { 204 return CKR_ATTRIBUTE_VALUE_INVALID; 205 } 206 data = (const unsigned char *)attribute->pValue; 207 for (i = 0; i < 4; i++) { 208 value |= (CK_ULONG)(data[i]) << ((3 - i) * 8); 209 } 210 211 *longData = value; 212 return CKR_OK; 213 } 214 215 /* 216 * ******************** Object Utilities ******************************* 217 */ 218 219 SECStatus 220 lg_deleteTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle) 221 { 222 SECItem *item; 223 PRBool rem; 224 PLHashTable *hashTable = lg_GetHashTable(sdb); 225 226 item = (SECItem *)PL_HashTableLookup(hashTable, (void *)handle); 227 rem = PL_HashTableRemove(hashTable, (void *)handle); 228 if (rem && item) { 229 SECITEM_FreeItem(item, PR_TRUE); 230 } 231 return rem ? SECSuccess : SECFailure; 232 } 233 234 /* must be called holding lg_DBLock(sdb) */ 235 static SECStatus 236 lg_addTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle, SECItem *key) 237 { 238 PLHashEntry *entry; 239 SECItem *item; 240 PLHashTable *hashTable = lg_GetHashTable(sdb); 241 242 item = SECITEM_DupItem(key); 243 if (item == NULL) { 244 return SECFailure; 245 } 246 entry = PL_HashTableAdd(hashTable, (void *)handle, item); 247 if (entry == NULL) { 248 SECITEM_FreeItem(item, PR_TRUE); 249 return SECFailure; 250 } 251 return SECSuccess; 252 } 253 254 /* must be called holding lg_DBLock(sdb) */ 255 const SECItem * 256 lg_lookupTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle) 257 { 258 PLHashTable *hashTable = lg_GetHashTable(sdb); 259 return (const SECItem *)PL_HashTableLookup(hashTable, (void *)handle); 260 } 261 262 static PRIntn 263 lg_freeHashItem(PLHashEntry *entry, PRIntn index, void *arg) 264 { 265 SECItem *item = (SECItem *)entry->value; 266 267 SECITEM_FreeItem(item, PR_TRUE); 268 return HT_ENUMERATE_NEXT; 269 } 270 271 CK_RV 272 lg_ClearTokenKeyHashTable(SDB *sdb) 273 { 274 PLHashTable *hashTable; 275 lg_DBLock(sdb); 276 hashTable = lg_GetHashTable(sdb); 277 PL_HashTableEnumerateEntries(hashTable, lg_freeHashItem, NULL); 278 lg_DBUnlock(sdb); 279 return CKR_OK; 280 } 281 282 /* 283 * handle Token Object stuff 284 */ 285 static void 286 lg_XORHash(unsigned char *key, unsigned char *dbkey, int len) 287 { 288 int i; 289 290 PORT_Memset(key, 0, 4); 291 292 for (i = 0; i < len - 4; i += 4) { 293 key[0] ^= dbkey[i]; 294 key[1] ^= dbkey[i + 1]; 295 key[2] ^= dbkey[i + 2]; 296 key[3] ^= dbkey[i + 3]; 297 } 298 } 299 300 /* Make a token handle for an object and record it so we can find it again */ 301 CK_OBJECT_HANDLE 302 lg_mkHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class) 303 { 304 unsigned char hashBuf[4]; 305 CK_OBJECT_HANDLE handle; 306 const SECItem *key; 307 308 handle = class; 309 /* there is only one KRL, use a fixed handle for it */ 310 if (handle != LG_TOKEN_KRL_HANDLE) { 311 lg_XORHash(hashBuf, dbKey->data, dbKey->len); 312 handle = ((CK_OBJECT_HANDLE)hashBuf[0] << 24) | 313 ((CK_OBJECT_HANDLE)hashBuf[1] << 16) | 314 ((CK_OBJECT_HANDLE)hashBuf[2] << 8) | 315 (CK_OBJECT_HANDLE)hashBuf[3]; 316 handle = class | (handle & ~(LG_TOKEN_TYPE_MASK | LG_TOKEN_MASK)); 317 /* we have a CRL who's handle has randomly matched the reserved KRL 318 * handle, increment it */ 319 if (handle == LG_TOKEN_KRL_HANDLE) { 320 handle++; 321 } 322 } 323 324 lg_DBLock(sdb); 325 while ((key = lg_lookupTokenKeyByHandle(sdb, handle)) != NULL) { 326 if (SECITEM_ItemsAreEqual(key, dbKey)) { 327 lg_DBUnlock(sdb); 328 return handle; 329 } 330 handle++; 331 } 332 lg_addTokenKeyByHandle(sdb, handle, dbKey); 333 lg_DBUnlock(sdb); 334 return handle; 335 } 336 337 PRBool 338 lg_poisonHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class) 339 { 340 unsigned char hashBuf[4]; 341 CK_OBJECT_HANDLE handle; 342 const SECItem *key; 343 344 handle = class; 345 /* there is only one KRL, use a fixed handle for it */ 346 if (handle != LG_TOKEN_KRL_HANDLE) { 347 lg_XORHash(hashBuf, dbKey->data, dbKey->len); 348 handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 349 (hashBuf[2] << 8) | hashBuf[3]; 350 handle = class | (handle & ~(LG_TOKEN_TYPE_MASK | LG_TOKEN_MASK)); 351 /* we have a CRL who's handle has randomly matched the reserved KRL 352 * handle, increment it */ 353 if (handle == LG_TOKEN_KRL_HANDLE) { 354 handle++; 355 } 356 } 357 lg_DBLock(sdb); 358 while ((key = lg_lookupTokenKeyByHandle(sdb, handle)) != NULL) { 359 if (SECITEM_ItemsAreEqual(key, dbKey)) { 360 key->data[0] ^= 0x80; 361 lg_DBUnlock(sdb); 362 return PR_TRUE; 363 } 364 handle++; 365 } 366 lg_DBUnlock(sdb); 367 return PR_FALSE; 368 } 369 370 static LGEncryptFunc lg_encrypt_stub = NULL; 371 static LGDecryptFunc lg_decrypt_stub = NULL; 372 373 void 374 legacy_SetCryptFunctions(LGEncryptFunc enc, LGDecryptFunc dec) 375 { 376 lg_encrypt_stub = enc; 377 lg_decrypt_stub = dec; 378 } 379 380 SECStatus 381 lg_util_encrypt(PLArenaPool *arena, SDB *sdb, 382 SECItem *plainText, SECItem **cipherText) 383 { 384 if (lg_encrypt_stub == NULL) { 385 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 386 return SECFailure; 387 } 388 return (*lg_encrypt_stub)(arena, sdb, plainText, cipherText); 389 } 390 391 SECStatus 392 lg_util_decrypt(SDB *sdb, SECItem *cipherText, SECItem **plainText) 393 { 394 if (lg_decrypt_stub == NULL) { 395 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 396 return SECFailure; 397 } 398 return (*lg_decrypt_stub)(sdb, cipherText, plainText); 399 }