1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/legacydb/lgutil.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,391 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include "lgdb.h" 1.8 +#include "secerr.h" 1.9 +#include "lgglue.h" 1.10 + 1.11 +/* 1.12 + * ******************** Attribute Utilities ******************************* 1.13 + */ 1.14 + 1.15 +/* 1.16 + * look up and attribute structure from a type and Object structure. 1.17 + * The returned attribute is referenced and needs to be freed when 1.18 + * it is no longer needed. 1.19 + */ 1.20 +const CK_ATTRIBUTE * 1.21 +lg_FindAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, 1.22 + CK_ULONG count ) 1.23 +{ 1.24 + unsigned int i; 1.25 + 1.26 + for (i=0; i < count; i++) { 1.27 + if (templ[i].type == type) { 1.28 + return &templ[i]; 1.29 + } 1.30 + } 1.31 + return NULL; 1.32 +} 1.33 + 1.34 + 1.35 +/* 1.36 + * return true if object has attribute 1.37 + */ 1.38 +PRBool 1.39 +lg_hasAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, 1.40 + CK_ULONG count ) 1.41 +{ 1.42 + if (lg_FindAttribute(type, templ, count) == NULL) { 1.43 + return PR_FALSE; 1.44 + } 1.45 + return PR_TRUE; 1.46 +} 1.47 + 1.48 +/* 1.49 + * copy an attribute into a SECItem. Secitem is allocated in the specified 1.50 + * arena. 1.51 + */ 1.52 +CK_RV 1.53 +lg_Attribute2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 1.54 + const CK_ATTRIBUTE *templ, CK_ULONG count, 1.55 + SECItem *item) 1.56 +{ 1.57 + int len; 1.58 + const CK_ATTRIBUTE *attribute; 1.59 + 1.60 + attribute = lg_FindAttribute(type, templ, count); 1.61 + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; 1.62 + len = attribute->ulValueLen; 1.63 + 1.64 + if (arena) { 1.65 + item->data = (unsigned char *) PORT_ArenaAlloc(arena,len); 1.66 + } else { 1.67 + item->data = (unsigned char *) PORT_Alloc(len); 1.68 + } 1.69 + if (item->data == NULL) { 1.70 + return CKR_HOST_MEMORY; 1.71 + } 1.72 + item->len = len; 1.73 + PORT_Memcpy(item->data, attribute->pValue, len); 1.74 + return CKR_OK; 1.75 +} 1.76 + 1.77 + 1.78 +/* 1.79 + * copy an unsigned attribute into a SECItem. Secitem is allocated in 1.80 + * the specified arena. 1.81 + */ 1.82 +CK_RV 1.83 +lg_Attribute2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 1.84 + const CK_ATTRIBUTE *templ, CK_ULONG count, 1.85 + SECItem *item) 1.86 +{ 1.87 + const CK_ATTRIBUTE *attribute; 1.88 + item->data = NULL; 1.89 + 1.90 + attribute = lg_FindAttribute(type, templ, count); 1.91 + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; 1.92 + 1.93 + (void)SECITEM_AllocItem(arena, item, attribute->ulValueLen); 1.94 + if (item->data == NULL) { 1.95 + return CKR_HOST_MEMORY; 1.96 + } 1.97 + PORT_Memcpy(item->data, attribute->pValue, item->len); 1.98 + return CKR_OK; 1.99 +} 1.100 + 1.101 +/* 1.102 + * copy an unsigned attribute into a SECItem. Secitem is allocated in 1.103 + * the specified arena. 1.104 + */ 1.105 +CK_RV 1.106 +lg_PrivAttr2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 1.107 + const CK_ATTRIBUTE *templ, CK_ULONG count, 1.108 + SECItem *item, SDB *sdbpw) 1.109 +{ 1.110 + const CK_ATTRIBUTE *attribute; 1.111 + SECItem epki, *dest = NULL; 1.112 + SECStatus rv; 1.113 + 1.114 + item->data = NULL; 1.115 + 1.116 + attribute = lg_FindAttribute(type, templ, count); 1.117 + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; 1.118 + 1.119 + epki.data = attribute->pValue; 1.120 + epki.len = attribute->ulValueLen; 1.121 + 1.122 + rv = lg_util_decrypt(sdbpw, &epki, &dest); 1.123 + if (rv != SECSuccess) { 1.124 + return CKR_USER_NOT_LOGGED_IN; 1.125 + } 1.126 + (void)SECITEM_AllocItem(arena, item, dest->len); 1.127 + if (item->data == NULL) { 1.128 + SECITEM_FreeItem(dest, PR_TRUE); 1.129 + return CKR_HOST_MEMORY; 1.130 + } 1.131 + 1.132 + PORT_Memcpy(item->data, dest->data, item->len); 1.133 + SECITEM_FreeItem(dest, PR_TRUE); 1.134 + return CKR_OK; 1.135 +} 1.136 + 1.137 +CK_RV 1.138 +lg_PrivAttr2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, 1.139 + const CK_ATTRIBUTE *templ, CK_ULONG count, 1.140 + SECItem *item, SDB *sdbpw) 1.141 +{ 1.142 + return lg_PrivAttr2SSecItem(arena, type, templ, count, item, sdbpw); 1.143 +} 1.144 + 1.145 +/* 1.146 + * this is only valid for CK_BBOOL type attributes. Return the state 1.147 + * of that attribute. 1.148 + */ 1.149 +PRBool 1.150 +lg_isTrue(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count) 1.151 +{ 1.152 + const CK_ATTRIBUTE *attribute; 1.153 + PRBool tok = PR_FALSE; 1.154 + 1.155 + attribute=lg_FindAttribute(type, templ, count); 1.156 + if (attribute == NULL) { return PR_FALSE; } 1.157 + tok = (PRBool)(*(CK_BBOOL *)attribute->pValue); 1.158 + 1.159 + return tok; 1.160 +} 1.161 + 1.162 +/* 1.163 + * return a null terminated string from attribute 'type'. This string 1.164 + * is allocated and needs to be freed with PORT_Free() When complete. 1.165 + */ 1.166 +char * 1.167 +lg_getString(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count) 1.168 +{ 1.169 + const CK_ATTRIBUTE *attribute; 1.170 + char *label = NULL; 1.171 + 1.172 + attribute = lg_FindAttribute(type, templ, count); 1.173 + if (attribute == NULL) return NULL; 1.174 + 1.175 + if (attribute->pValue != NULL) { 1.176 + label = (char *) PORT_Alloc(attribute->ulValueLen+1); 1.177 + if (label == NULL) { 1.178 + return NULL; 1.179 + } 1.180 + 1.181 + PORT_Memcpy(label,attribute->pValue, attribute->ulValueLen); 1.182 + label[attribute->ulValueLen] = 0; 1.183 + } 1.184 + return label; 1.185 +} 1.186 + 1.187 +CK_RV 1.188 +lg_GetULongAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, 1.189 + CK_ULONG count, CK_ULONG *longData) 1.190 +{ 1.191 + const CK_ATTRIBUTE *attribute; 1.192 + CK_ULONG value = 0; 1.193 + const unsigned char *data; 1.194 + int i; 1.195 + 1.196 + attribute = lg_FindAttribute(type, templ, count); 1.197 + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; 1.198 + 1.199 + if (attribute->ulValueLen != 4) { 1.200 + return CKR_ATTRIBUTE_VALUE_INVALID; 1.201 + } 1.202 + data = (const unsigned char *)attribute->pValue; 1.203 + for (i=0; i < 4; i++) { 1.204 + value |= (CK_ULONG)(data[i]) << ((3-i)*8); 1.205 + } 1.206 + 1.207 + *longData = value; 1.208 + return CKR_OK; 1.209 +} 1.210 + 1.211 +/* 1.212 + * ******************** Object Utilities ******************************* 1.213 + */ 1.214 + 1.215 +SECStatus 1.216 +lg_deleteTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle) 1.217 +{ 1.218 + SECItem *item; 1.219 + PRBool rem; 1.220 + PLHashTable *hashTable= lg_GetHashTable(sdb); 1.221 + 1.222 + item = (SECItem *)PL_HashTableLookup(hashTable, (void *)handle); 1.223 + rem = PL_HashTableRemove(hashTable,(void *)handle) ; 1.224 + if (rem && item) { 1.225 + SECITEM_FreeItem(item,PR_TRUE); 1.226 + } 1.227 + return rem ? SECSuccess : SECFailure; 1.228 +} 1.229 + 1.230 +/* must be called holding lg_DBLock(sdb) */ 1.231 +static SECStatus 1.232 +lg_addTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle, SECItem *key) 1.233 +{ 1.234 + PLHashEntry *entry; 1.235 + SECItem *item; 1.236 + PLHashTable *hashTable= lg_GetHashTable(sdb); 1.237 + 1.238 + item = SECITEM_DupItem(key); 1.239 + if (item == NULL) { 1.240 + return SECFailure; 1.241 + } 1.242 + entry = PL_HashTableAdd(hashTable,(void *)handle,item); 1.243 + if (entry == NULL) { 1.244 + SECITEM_FreeItem(item,PR_TRUE); 1.245 + return SECFailure; 1.246 + } 1.247 + return SECSuccess; 1.248 +} 1.249 + 1.250 +/* must be called holding lg_DBLock(sdb) */ 1.251 +const SECItem * 1.252 +lg_lookupTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle) 1.253 +{ 1.254 + PLHashTable *hashTable= lg_GetHashTable(sdb); 1.255 + return (const SECItem *)PL_HashTableLookup(hashTable, (void *)handle); 1.256 +} 1.257 + 1.258 + 1.259 +static PRIntn 1.260 +lg_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg) 1.261 +{ 1.262 + SECItem *item = (SECItem *)entry->value; 1.263 + 1.264 + SECITEM_FreeItem(item, PR_TRUE); 1.265 + return HT_ENUMERATE_NEXT; 1.266 +} 1.267 + 1.268 +CK_RV 1.269 +lg_ClearTokenKeyHashTable(SDB *sdb) 1.270 +{ 1.271 + PLHashTable *hashTable; 1.272 + lg_DBLock(sdb); 1.273 + hashTable= lg_GetHashTable(sdb); 1.274 + PL_HashTableEnumerateEntries(hashTable, lg_freeHashItem, NULL); 1.275 + lg_DBUnlock(sdb); 1.276 + return CKR_OK; 1.277 +} 1.278 + 1.279 +/* 1.280 + * handle Token Object stuff 1.281 + */ 1.282 +static void 1.283 +lg_XORHash(unsigned char *key, unsigned char *dbkey, int len) 1.284 +{ 1.285 + int i; 1.286 + 1.287 + PORT_Memset(key, 0, 4); 1.288 + 1.289 + for (i=0; i < len-4; i += 4) { 1.290 + key[0] ^= dbkey[i]; 1.291 + key[1] ^= dbkey[i+1]; 1.292 + key[2] ^= dbkey[i+2]; 1.293 + key[3] ^= dbkey[i+3]; 1.294 + } 1.295 +} 1.296 + 1.297 +/* Make a token handle for an object and record it so we can find it again */ 1.298 +CK_OBJECT_HANDLE 1.299 +lg_mkHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class) 1.300 +{ 1.301 + unsigned char hashBuf[4]; 1.302 + CK_OBJECT_HANDLE handle; 1.303 + const SECItem *key; 1.304 + 1.305 + handle = class; 1.306 + /* there is only one KRL, use a fixed handle for it */ 1.307 + if (handle != LG_TOKEN_KRL_HANDLE) { 1.308 + lg_XORHash(hashBuf,dbKey->data,dbKey->len); 1.309 + handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 1.310 + (hashBuf[2] << 8) | hashBuf[3]; 1.311 + handle = class | (handle & ~(LG_TOKEN_TYPE_MASK|LG_TOKEN_MASK)); 1.312 + /* we have a CRL who's handle has randomly matched the reserved KRL 1.313 + * handle, increment it */ 1.314 + if (handle == LG_TOKEN_KRL_HANDLE) { 1.315 + handle++; 1.316 + } 1.317 + } 1.318 + 1.319 + lg_DBLock(sdb); 1.320 + while ((key = lg_lookupTokenKeyByHandle(sdb,handle)) != NULL) { 1.321 + if (SECITEM_ItemsAreEqual(key,dbKey)) { 1.322 + lg_DBUnlock(sdb); 1.323 + return handle; 1.324 + } 1.325 + handle++; 1.326 + } 1.327 + lg_addTokenKeyByHandle(sdb,handle,dbKey); 1.328 + lg_DBUnlock(sdb); 1.329 + return handle; 1.330 +} 1.331 + 1.332 +PRBool 1.333 +lg_poisonHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class) 1.334 +{ 1.335 + unsigned char hashBuf[4]; 1.336 + CK_OBJECT_HANDLE handle; 1.337 + const SECItem *key; 1.338 + 1.339 + handle = class; 1.340 + /* there is only one KRL, use a fixed handle for it */ 1.341 + if (handle != LG_TOKEN_KRL_HANDLE) { 1.342 + lg_XORHash(hashBuf,dbKey->data,dbKey->len); 1.343 + handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 1.344 + (hashBuf[2] << 8) | hashBuf[3]; 1.345 + handle = class | (handle & ~(LG_TOKEN_TYPE_MASK|LG_TOKEN_MASK)); 1.346 + /* we have a CRL who's handle has randomly matched the reserved KRL 1.347 + * handle, increment it */ 1.348 + if (handle == LG_TOKEN_KRL_HANDLE) { 1.349 + handle++; 1.350 + } 1.351 + } 1.352 + lg_DBLock(sdb); 1.353 + while ((key = lg_lookupTokenKeyByHandle(sdb,handle)) != NULL) { 1.354 + if (SECITEM_ItemsAreEqual(key,dbKey)) { 1.355 + key->data[0] ^= 0x80; 1.356 + lg_DBUnlock(sdb); 1.357 + return PR_TRUE; 1.358 + } 1.359 + handle++; 1.360 + } 1.361 + lg_DBUnlock(sdb); 1.362 + return PR_FALSE; 1.363 +} 1.364 + 1.365 +static LGEncryptFunc lg_encrypt_stub = NULL; 1.366 +static LGDecryptFunc lg_decrypt_stub = NULL; 1.367 + 1.368 +void 1.369 +legacy_SetCryptFunctions(LGEncryptFunc enc, LGDecryptFunc dec) 1.370 +{ 1.371 + lg_encrypt_stub = enc; 1.372 + lg_decrypt_stub = dec; 1.373 +} 1.374 + 1.375 +SECStatus lg_util_encrypt(PLArenaPool *arena, SDB *sdb, 1.376 + SECItem *plainText, SECItem **cipherText) 1.377 +{ 1.378 + if (lg_encrypt_stub == NULL) { 1.379 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.380 + return SECFailure; 1.381 + } 1.382 + return (*lg_encrypt_stub)(arena, sdb, plainText, cipherText); 1.383 +} 1.384 + 1.385 +SECStatus lg_util_decrypt(SDB *sdb, SECItem *cipherText, SECItem **plainText) 1.386 +{ 1.387 + if (lg_decrypt_stub == NULL) { 1.388 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.389 + return SECFailure; 1.390 + } 1.391 + return (*lg_decrypt_stub)(sdb, cipherText, plainText); 1.392 +} 1.393 + 1.394 +