diff nss/lib/softoken/legacydb/lgutil.c @ 3:150b72113545

Add DBM and legacydb support
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 05 Aug 2014 18:32:02 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/softoken/legacydb/lgutil.c	Tue Aug 05 18:32:02 2014 +0200
@@ -0,0 +1,391 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "lgdb.h"
+#include "secerr.h"
+#include "lgglue.h"
+
+/*
+ * ******************** Attribute Utilities *******************************
+ */
+
+/*
+ * look up and attribute structure from a type and Object structure.
+ * The returned attribute is referenced and needs to be freed when 
+ * it is no longer needed.
+ */
+const CK_ATTRIBUTE *
+lg_FindAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ,
+		 CK_ULONG count )
+{
+    unsigned int i;
+
+    for (i=0; i < count; i++) {
+	if (templ[i].type == type) {
+	    return &templ[i];
+	}
+    }
+    return NULL;
+}
+
+
+/*
+ * return true if object has attribute
+ */
+PRBool
+lg_hasAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ,
+		 CK_ULONG count )
+{
+   if (lg_FindAttribute(type, templ, count) == NULL) {
+	return PR_FALSE;
+   }
+   return PR_TRUE;
+}
+
+/* 
+ * copy an attribute into a SECItem. Secitem is allocated in the specified
+ * arena.
+ */
+CK_RV
+lg_Attribute2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
+			const CK_ATTRIBUTE *templ, CK_ULONG count,
+			SECItem *item)
+{
+    int len;
+    const CK_ATTRIBUTE *attribute;
+
+    attribute = lg_FindAttribute(type, templ, count);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+    len = attribute->ulValueLen;
+
+    if (arena) {
+    	item->data = (unsigned char *) PORT_ArenaAlloc(arena,len);
+    } else {
+    	item->data = (unsigned char *) PORT_Alloc(len);
+    }
+    if (item->data == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    item->len = len;
+    PORT_Memcpy(item->data, attribute->pValue, len);
+    return CKR_OK;
+}
+
+
+/* 
+ * copy an unsigned attribute into a SECItem. Secitem is allocated in
+ * the specified arena.
+ */
+CK_RV
+lg_Attribute2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
+			const CK_ATTRIBUTE *templ, CK_ULONG count,
+			SECItem *item)
+{
+    const CK_ATTRIBUTE *attribute;
+    item->data = NULL;
+
+    attribute = lg_FindAttribute(type, templ, count);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+
+    (void)SECITEM_AllocItem(arena, item, attribute->ulValueLen);
+    if (item->data == NULL) {
+	return CKR_HOST_MEMORY;
+    }
+    PORT_Memcpy(item->data, attribute->pValue, item->len);
+    return CKR_OK;
+}
+
+/* 
+ * copy an unsigned attribute into a SECItem. Secitem is allocated in
+ * the specified arena.
+ */
+CK_RV
+lg_PrivAttr2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
+			const CK_ATTRIBUTE *templ, CK_ULONG count,
+			SECItem *item, SDB *sdbpw)
+{
+    const CK_ATTRIBUTE *attribute;
+    SECItem epki, *dest = NULL;
+    SECStatus rv;
+
+    item->data = NULL;
+
+    attribute = lg_FindAttribute(type, templ, count);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+
+    epki.data = attribute->pValue;
+    epki.len = attribute->ulValueLen;
+
+    rv = lg_util_decrypt(sdbpw, &epki, &dest);
+    if (rv != SECSuccess) {
+	return CKR_USER_NOT_LOGGED_IN;
+    }
+    (void)SECITEM_AllocItem(arena, item, dest->len);
+    if (item->data == NULL) {
+	SECITEM_FreeItem(dest, PR_TRUE);
+	return CKR_HOST_MEMORY;
+    }
+    
+    PORT_Memcpy(item->data, dest->data, item->len);
+    SECITEM_FreeItem(dest, PR_TRUE);
+    return CKR_OK;
+}
+
+CK_RV
+lg_PrivAttr2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
+			const CK_ATTRIBUTE *templ, CK_ULONG count,
+			SECItem *item, SDB *sdbpw)
+{
+    return lg_PrivAttr2SSecItem(arena, type, templ, count, item, sdbpw);
+}
+
+/*
+ * this is only valid for CK_BBOOL type attributes. Return the state
+ * of that attribute.
+ */
+PRBool
+lg_isTrue(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count)
+{
+    const CK_ATTRIBUTE *attribute;
+    PRBool tok = PR_FALSE;
+
+    attribute=lg_FindAttribute(type, templ, count);
+    if (attribute == NULL) { return PR_FALSE; }
+    tok = (PRBool)(*(CK_BBOOL *)attribute->pValue);
+
+    return tok;
+}
+
+/*
+ * return a null terminated string from attribute 'type'. This string
+ * is allocated and needs to be freed with PORT_Free() When complete.
+ */
+char *
+lg_getString(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count)
+{
+    const CK_ATTRIBUTE *attribute;
+    char *label = NULL;
+
+    attribute = lg_FindAttribute(type, templ, count);
+    if (attribute == NULL) return NULL;
+
+    if (attribute->pValue != NULL) {
+	label = (char *) PORT_Alloc(attribute->ulValueLen+1);
+	if (label == NULL) {
+	    return NULL;
+	}
+
+	PORT_Memcpy(label,attribute->pValue, attribute->ulValueLen);
+	label[attribute->ulValueLen] = 0;
+    }
+    return label;
+}
+
+CK_RV
+lg_GetULongAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ,
+				 CK_ULONG count, CK_ULONG *longData)
+{
+    const CK_ATTRIBUTE *attribute;
+    CK_ULONG value = 0;
+    const unsigned char *data;
+    int i;
+
+    attribute = lg_FindAttribute(type, templ, count);
+    if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
+
+    if (attribute->ulValueLen != 4) {
+	return CKR_ATTRIBUTE_VALUE_INVALID;
+    }
+    data = (const unsigned char *)attribute->pValue;
+    for (i=0; i < 4; i++) {
+	value |= (CK_ULONG)(data[i]) << ((3-i)*8);
+    }
+
+    *longData = value;
+    return CKR_OK;
+}
+
+/*
+ * ******************** Object Utilities *******************************
+ */
+
+SECStatus
+lg_deleteTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle)
+{
+    SECItem *item;
+    PRBool rem;
+    PLHashTable *hashTable= lg_GetHashTable(sdb);
+
+    item = (SECItem *)PL_HashTableLookup(hashTable, (void *)handle);
+    rem = PL_HashTableRemove(hashTable,(void *)handle) ;
+    if (rem && item) {
+	SECITEM_FreeItem(item,PR_TRUE);
+    }
+    return rem ? SECSuccess : SECFailure;
+}
+
+/* must be called holding lg_DBLock(sdb) */
+static SECStatus
+lg_addTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle, SECItem *key)
+{
+    PLHashEntry *entry;
+    SECItem *item;
+    PLHashTable *hashTable= lg_GetHashTable(sdb);
+
+    item = SECITEM_DupItem(key);
+    if (item == NULL) {
+	return SECFailure;
+    }
+    entry = PL_HashTableAdd(hashTable,(void *)handle,item);
+    if (entry == NULL) {
+	SECITEM_FreeItem(item,PR_TRUE);
+	return SECFailure;
+    }
+    return SECSuccess;
+}
+
+/* must be called holding lg_DBLock(sdb) */
+const SECItem *
+lg_lookupTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle)
+{
+    PLHashTable *hashTable= lg_GetHashTable(sdb);
+    return (const SECItem *)PL_HashTableLookup(hashTable, (void *)handle);
+}
+
+
+static PRIntn
+lg_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg)
+{
+    SECItem *item = (SECItem *)entry->value;
+
+    SECITEM_FreeItem(item, PR_TRUE);
+    return HT_ENUMERATE_NEXT;
+}
+
+CK_RV
+lg_ClearTokenKeyHashTable(SDB *sdb)
+{
+    PLHashTable *hashTable;
+    lg_DBLock(sdb);
+    hashTable= lg_GetHashTable(sdb);
+    PL_HashTableEnumerateEntries(hashTable, lg_freeHashItem, NULL);
+    lg_DBUnlock(sdb);
+    return CKR_OK;
+}
+
+/*
+ * handle Token Object stuff
+ */
+static void
+lg_XORHash(unsigned char *key, unsigned char *dbkey, int len)
+{
+   int i;
+
+   PORT_Memset(key, 0, 4);
+
+   for (i=0; i < len-4; i += 4) {
+	key[0] ^= dbkey[i];
+	key[1] ^= dbkey[i+1];
+	key[2] ^= dbkey[i+2];
+	key[3] ^= dbkey[i+3];
+   }
+}
+
+/* Make a token handle for an object and record it so we can find it again */
+CK_OBJECT_HANDLE
+lg_mkHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class)
+{
+    unsigned char hashBuf[4];
+    CK_OBJECT_HANDLE handle;
+    const SECItem *key;
+
+    handle = class;
+    /* there is only one KRL, use a fixed handle for it */
+    if (handle != LG_TOKEN_KRL_HANDLE) {
+	lg_XORHash(hashBuf,dbKey->data,dbKey->len);
+	handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 
+					(hashBuf[2] << 8)  | hashBuf[3];
+	handle =  class | (handle & ~(LG_TOKEN_TYPE_MASK|LG_TOKEN_MASK));
+	/* we have a CRL who's handle has randomly matched the reserved KRL
+	 * handle, increment it */
+	if (handle == LG_TOKEN_KRL_HANDLE) {
+	    handle++;
+	}
+    }
+
+    lg_DBLock(sdb);
+    while ((key = lg_lookupTokenKeyByHandle(sdb,handle)) != NULL) {
+	if (SECITEM_ItemsAreEqual(key,dbKey)) {
+    	   lg_DBUnlock(sdb);
+	   return handle;
+	}
+	handle++;
+    }
+    lg_addTokenKeyByHandle(sdb,handle,dbKey);
+    lg_DBUnlock(sdb);
+    return handle;
+}
+
+PRBool
+lg_poisonHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class)
+{
+    unsigned char hashBuf[4];
+    CK_OBJECT_HANDLE handle;
+    const SECItem *key;
+
+    handle = class;
+    /* there is only one KRL, use a fixed handle for it */
+    if (handle != LG_TOKEN_KRL_HANDLE) {
+	lg_XORHash(hashBuf,dbKey->data,dbKey->len);
+	handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | 
+					(hashBuf[2] << 8)  | hashBuf[3];
+	handle = class | (handle & ~(LG_TOKEN_TYPE_MASK|LG_TOKEN_MASK));
+	/* we have a CRL who's handle has randomly matched the reserved KRL
+	 * handle, increment it */
+	if (handle == LG_TOKEN_KRL_HANDLE) {
+	    handle++;
+	}
+    }
+    lg_DBLock(sdb);
+    while ((key = lg_lookupTokenKeyByHandle(sdb,handle)) != NULL) {
+	if (SECITEM_ItemsAreEqual(key,dbKey)) {
+	   key->data[0] ^= 0x80;
+    	   lg_DBUnlock(sdb);
+	   return PR_TRUE;
+	}
+	handle++;
+    }
+    lg_DBUnlock(sdb);
+    return PR_FALSE;
+}
+
+static LGEncryptFunc lg_encrypt_stub = NULL;
+static LGDecryptFunc lg_decrypt_stub = NULL;
+
+void
+legacy_SetCryptFunctions(LGEncryptFunc enc, LGDecryptFunc dec)
+{
+   lg_encrypt_stub = enc;
+   lg_decrypt_stub = dec;
+}
+
+SECStatus lg_util_encrypt(PLArenaPool *arena, SDB *sdb, 
+			  SECItem *plainText, SECItem **cipherText)
+{
+    if (lg_encrypt_stub == NULL) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return (*lg_encrypt_stub)(arena, sdb, plainText, cipherText);
+}
+
+SECStatus lg_util_decrypt(SDB *sdb, SECItem *cipherText, SECItem **plainText)
+{
+    if (lg_decrypt_stub == NULL) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    return (*lg_decrypt_stub)(sdb, cipherText, plainText);
+}
+
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)