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