/* store result in a temporary list, avoid recursive operation */
raw = linked_list_create();
- /* do not use trusted argument if not supported */
- if (!(this->lib->get_features(this->lib) & PKCS11_TRUSTED_CERTS))
- {
- count--;
- }
enumerator = this->lib->create_object_enumerator(this->lib,
session, tmpl, countof(tmpl), attr, count);
while (enumerator->enumerate(enumerator, &object))
{
- entry = malloc(sizeof(*entry));
- entry->value = chunk_clone(
- chunk_create(attr[0].pValue, attr[0].ulValueLen));
- entry->label = chunk_clone(
- chunk_create(attr[1].pValue, attr[1].ulValueLen));
- entry->trusted = trusted;
+ if (attr[0].ulValueLen == CK_UNAVAILABLE_INFORMATION ||
+ attr[1].ulValueLen == CK_UNAVAILABLE_INFORMATION)
+ {
+ continue;
+ }
+ INIT(entry,
+ .value = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen)),
+ .label = chunk_clone(chunk_create(attr[1].pValue, attr[1].ulValueLen)),
+ /* assume trusted certificates if attribute is not available */
+ .trusted = attr[2].ulValueLen == CK_UNAVAILABLE_INFORMATION || trusted,
+ );
raw->insert_last(raw, entry);
}
enumerator->destroy(enumerator);
}
certs = p11->create_object_enumerator(p11, session,
tmpl, countof(tmpl), attr, countof(attr));
- if (certs->enumerate(certs, &object))
+ if (certs->enumerate(certs, &object) &&
+ attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION)
{
data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
}
pkcs11_library_t *lib;
/* attributes to retrieve */
CK_ATTRIBUTE_PTR attr;
+ /* copy of the original attributes provided by the caller */
+ CK_ATTRIBUTE_PTR orig_attr;
/* number of attributes */
CK_ULONG count;
/* object handle in case of a single object */
} object_enumerator_t;
/**
- * Free contents of attributes in a list
+ * Keep a copy of the original attribute values so we can restore them while
+ * enumerating e.g. if an attribute was unavailable for a particular object.
+ */
+static void init_attrs(object_enumerator_t *this)
+{
+ int i;
+
+ this->orig_attr = calloc(this->count, sizeof(CK_ATTRIBUTE));
+ for (i = 0; i < this->count; i++)
+ {
+ this->orig_attr[i] = this->attr[i];
+ }
+}
+
+/**
+ * Free contents of allocated attributes and reset them to their original
+ * values.
*/
static void free_attrs(object_enumerator_t *this)
{
CK_ATTRIBUTE_PTR attr;
+ int i;
while (this->freelist->remove_last(this->freelist, (void**)&attr) == SUCCESS)
{
free(attr->pValue);
- attr->pValue = NULL;
- attr->ulValueLen = 0;
+ }
+ for (i = 0; i < this->count; i++)
+ {
+ this->attr[i] = this->orig_attr[i];
}
}
/* get length of objects first */
rv = this->lib->f->C_GetAttributeValue(this->session, object,
this->attr, this->count);
- if (rv != CKR_OK)
+ if (rv != CKR_OK &&
+ rv != CKR_ATTRIBUTE_SENSITIVE &&
+ rv != CKR_ATTRIBUTE_TYPE_INVALID)
{
DBG1(DBG_CFG, "C_GetAttributeValue(NULL) error: %N", ck_rv_names, rv);
return FALSE;
/* allocate required chunks */
for (i = 0; i < this->count; i++)
{
- if (this->attr[i].pValue == NULL &&
- this->attr[i].ulValueLen != 0 && this->attr[i].ulValueLen != -1)
+ if (this->attr[i].ulValueLen == CK_UNAVAILABLE_INFORMATION)
+ { /* reset this unavailable attribute before the next call */
+ this->attr[i] = this->orig_attr[i];
+ }
+ else if (this->attr[i].pValue == NULL &&
+ this->attr[i].ulValueLen != 0)
{
this->attr[i].pValue = malloc(this->attr[i].ulValueLen);
this->freelist->insert_last(this->freelist, &this->attr[i]);
/* get the data */
rv = this->lib->f->C_GetAttributeValue(this->session, object,
this->attr, this->count);
- if (rv != CKR_OK)
+ if (rv != CKR_OK &&
+ rv != CKR_ATTRIBUTE_SENSITIVE &&
+ rv != CKR_ATTRIBUTE_TYPE_INVALID)
{
- free_attrs(this);
DBG1(DBG_CFG, "C_GetAttributeValue() error: %N", ck_rv_names, rv);
return FALSE;
}
}
free_attrs(this);
this->freelist->destroy(this->freelist);
+ free(this->orig_attr);
free(this);
}
.count = acount,
.freelist = linked_list_create(),
);
+ init_attrs(enumerator);
return &enumerator->public;
}
.object = object,
.freelist = linked_list_create(),
);
+ init_attrs(enumerator);
return &enumerator->public;
}
{
if (has_version(info, 2, 20))
{
- this->features |= PKCS11_TRUSTED_CERTS;
this->features |= PKCS11_ALWAYS_AUTH_KEYS;
}
}
* Optional PKCS#11 features some libraries support, some not
*/
enum pkcs11_feature_t {
- /** CKA_TRUSTED attribute supported for certificate objects */
- PKCS11_TRUSTED_CERTS = (1<<0),
/** CKA_ALWAYS_AUTHENTICATE attribute supported for private keys */
- PKCS11_ALWAYS_AUTH_KEYS = (1<<1),
+ PKCS11_ALWAYS_AUTH_KEYS = (1<<0),
};
/**
* An optional attribute array is automatically filled in with the
* objects associated attributes. If the value of an output attribute
* is NULL, the value gets allocated/freed during enumeration.
+ * For attributes that are unavailable, the length field will be set to
+ * CK_UNAVAILABLE_INFORMATION.
*
* @param session session to use
* @param tmpl search template
* The given attribute array is automatically filled in with the
* associated attributes. If the value of an output attribute is NULL,
* the required memory gets allocated/freed during enumeration.
+ * For attributes that are unavailable, the length field will be set to
+ * CK_UNAVAILABLE_INFORMATION.
*
* @param session session to use
* @param object object handle
return &this->public;
}
-
attr, countof(attr));
while (certs->enumerate(certs, &object))
{
- INIT(entry,
- .value = chunk_clone(
- chunk_create(attr[0].pValue, attr[0].ulValueLen)),
- .ckaid = chunk_clone(
- chunk_create(attr[1].pValue, attr[1].ulValueLen)),
- );
- raw->insert_last(raw, entry);
+ if (attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION &&
+ attr[1].ulValueLen != CK_UNAVAILABLE_INFORMATION)
+ {
+ INIT(entry,
+ .value = chunk_clone(
+ chunk_create(attr[0].pValue, attr[0].ulValueLen)),
+ .ckaid = chunk_clone(
+ chunk_create(attr[1].pValue, attr[1].ulValueLen)),
+ );
+ raw->insert_last(raw, entry);
+ }
}
certs->destroy(certs);
}
enumerator = this->lib->create_object_enumerator(this->lib,
this->session, tmpl, countof(tmpl), attr, count);
- if (enumerator->enumerate(enumerator, &object))
+ if (enumerator->enumerate(enumerator, &object) &&
+ attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION)
{
this->type = KEY_RSA;
switch (type)
this->type = KEY_ECDSA;
/* fall-through */
case CKK_RSA:
- this->reauth = reauth;
+ if (attr[1].ulValueLen != CK_UNAVAILABLE_INFORMATION)
+ {
+ this->reauth = reauth;
+ }
this->object = object;
found = TRUE;
break;
enumerator = this->lib->create_object_enumerator(this->lib, this->session,
tmpl, countof(tmpl), attr, countof(attr));
- if (enumerator->enumerate(enumerator, &object))
+ if (enumerator->enumerate(enumerator, &object) &&
+ attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION)
{
data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
}
enumerator = p11->create_object_enumerator(p11, session, tmpl, count, attr,
countof(attr));
- if (enumerator->enumerate(enumerator, &object))
+ if (enumerator->enumerate(enumerator, &object) &&
+ attr[0].ulValueLen != CK_UNAVAILABLE_INFORMATION)
{
switch (type)
{