/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* GIO - Small GLib wrapper of PKCS#11 for use in GTls
*
* Copyright 2011 Collabora, Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* In addition, when the library is used with OpenSSL, a special
* exception applies. Refer to the LICENSE_EXCEPTION file for details.
*
* Author: Stef Walter <stefw@collabora.co.uk>
*/
#include "config.h"
#include "gpkcs11array.h"
#include <string.h>
G_DEFINE_BOXED_TYPE (GPkcs11Array, g_pkcs11_array, g_pkcs11_array_ref, g_pkcs11_array_unref);
typedef struct _GRealPkcs11Array
{
CK_ATTRIBUTE *attrs;
CK_ULONG len;
volatile gint ref_count;
} GRealPkcs11Array;
GPkcs11Array*
g_pkcs11_array_new (void)
{
GRealPkcs11Array *array = g_slice_new (GRealPkcs11Array);
array->attrs = NULL;
array->len = 0;
array->ref_count = 1;
return (GPkcs11Array*) array;
}
void
g_pkcs11_array_add (GPkcs11Array *array,
CK_ATTRIBUTE *attr)
{
GRealPkcs11Array *rarray = (GRealPkcs11Array*)array;
g_return_if_fail (array);
g_return_if_fail (attr);
g_return_if_fail (attr->ulValueLen != (CK_ATTRIBUTE_TYPE)-1 || !attr->pValue);
g_return_if_fail (attr->pValue || !attr->ulValueLen);
rarray->attrs = g_renew (CK_ATTRIBUTE, rarray->attrs, rarray->len + 1);
memcpy (rarray->attrs + rarray->len, attr, sizeof (CK_ATTRIBUTE));
if (attr->pValue)
rarray->attrs[rarray->len].pValue = g_memdup (attr->pValue, attr->ulValueLen);
rarray->len++;
}
void
g_pkcs11_array_add_value (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type,
gconstpointer value,
gssize length)
{
CK_ATTRIBUTE attr;
g_return_if_fail (array);
if (length < 0)
length = strlen (value);
attr.type = type;
attr.pValue = (gpointer)value;
attr.ulValueLen = length;
g_pkcs11_array_add (array, &attr);
}
void
g_pkcs11_array_add_boolean (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE attr_type,
gboolean value)
{
CK_ATTRIBUTE attr;
CK_BBOOL bval;
g_return_if_fail (array);
bval = value ? CK_TRUE : CK_FALSE;
attr.type = attr_type;
attr.pValue = &bval;
attr.ulValueLen = sizeof (bval);
g_pkcs11_array_add (array, &attr);
}
void
g_pkcs11_array_add_ulong (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type,
gulong value)
{
CK_ATTRIBUTE attr;
CK_ULONG uval;
g_return_if_fail (array);
uval = value;
attr.type = type;
attr.pValue = &uval;
attr.ulValueLen = sizeof (uval);
g_pkcs11_array_add (array, &attr);
}
void
g_pkcs11_array_set (GPkcs11Array *array,
CK_ATTRIBUTE *attr)
{
CK_ATTRIBUTE *previous;
g_return_if_fail (array);
g_return_if_fail (attr);
g_return_if_fail (attr->ulValueLen != (CK_ATTRIBUTE_TYPE)-1 || !attr->pValue);
g_return_if_fail (attr->pValue || !attr->ulValueLen);
previous = (CK_ATTRIBUTE*)g_pkcs11_array_find (array, attr->type);
if (previous == NULL)
{
g_pkcs11_array_add (array, attr);
}
else
{
g_free (previous->pValue);
previous->pValue = g_memdup (attr->pValue, attr->ulValueLen);
previous->ulValueLen = attr->ulValueLen;
}
}
void
g_pkcs11_array_set_value (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type,
gconstpointer value,
gssize length)
{
CK_ATTRIBUTE attr;
g_return_if_fail (array);
if (length < 0)
length = strlen (value);
attr.type = type;
attr.pValue = (gpointer)value;
attr.ulValueLen = length;
g_pkcs11_array_set (array, &attr);
}
void
g_pkcs11_array_set_boolean (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE attr_type,
gboolean value)
{
CK_ATTRIBUTE attr;
CK_BBOOL bval;
g_return_if_fail (array);
bval = value ? CK_TRUE : CK_FALSE;
attr.type = attr_type;
attr.pValue = &bval;
attr.ulValueLen = sizeof (bval);
g_pkcs11_array_set (array, &attr);
}
void
g_pkcs11_array_set_ulong (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type,
gulong value)
{
CK_ATTRIBUTE attr;
CK_ULONG uval;
g_return_if_fail (array);
uval = value;
attr.type = type;
attr.pValue = &uval;
attr.ulValueLen = sizeof (uval);
g_pkcs11_array_set (array, &attr);
}
const CK_ATTRIBUTE*
g_pkcs11_array_find (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type)
{
const CK_ATTRIBUTE* attr;
guint i;
g_return_val_if_fail (array, NULL);
for (i = 0; i < array->count; ++i)
{
attr = &g_pkcs11_array_index (array, i);
if (attr->type == type)
return attr;
}
return NULL;
}
gboolean
g_pkcs11_array_find_boolean (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type,
gboolean *value)
{
const CK_ATTRIBUTE* attr;
g_return_val_if_fail (array, FALSE);
g_return_val_if_fail (value, FALSE);
attr = g_pkcs11_array_find (array, type);
if (!attr || !attr->pValue || attr->ulValueLen != sizeof (CK_BBOOL))
return FALSE;
*value = *((CK_BBOOL*)attr->pValue) ? TRUE : FALSE;
return TRUE;
}
gboolean
g_pkcs11_array_find_ulong (GPkcs11Array *array,
CK_ATTRIBUTE_TYPE type,
gulong *value)
{
const CK_ATTRIBUTE* attr;
g_return_val_if_fail (array, FALSE);
g_return_val_if_fail (value, FALSE);
attr = g_pkcs11_array_find (array, type);
if (!attr || !attr->pValue || attr->ulValueLen != sizeof (CK_ULONG))
return FALSE;
*value = *((CK_ULONG*)attr->pValue);
return TRUE;
}
GPkcs11Array*
g_pkcs11_array_ref (GPkcs11Array *array)
{
GRealPkcs11Array *rarray = (GRealPkcs11Array*) array;
g_return_val_if_fail (array, NULL);
g_return_val_if_fail (g_atomic_int_get (&rarray->ref_count) > 0, array);
g_atomic_int_inc (&rarray->ref_count);
return array;
}
void
g_pkcs11_array_unref (GPkcs11Array *array)
{
GRealPkcs11Array *rarray = (GRealPkcs11Array*) array;
CK_ULONG i;
g_return_if_fail (array);
g_return_if_fail (g_atomic_int_get (&rarray->ref_count) > 0);
if (g_atomic_int_dec_and_test (&rarray->ref_count))
{
for (i = 0; i < rarray->len; ++i)
g_free (rarray->attrs[i].pValue);
g_free (rarray->attrs);
g_slice_free1 (sizeof (GRealPkcs11Array), array);
}
}