808bits

CKR_ATTRIBUTE_READ_ONLY

PKCS#11 return value · 0x00000010 · decimal 16
hex 0x00000010 decimal 16 name CKR_ATTRIBUTE_READ_ONLY

Some attributes are decided by the token, some are fixed once the object exists, and some become fixed because the object was created with modifiable false. This code covers all three, on a set call and on a create or copy template alike, which is why the same attribute can be fine in one call and refused in the next. The specification marks the rules with footnotes in its attribute tables, and almost nobody reads them.

What the token is reporting

The template names an attribute that cannot be set in this call. Either it is read-only by definition, read-only once the object exists, or the object as a whole is not modifiable.

Likely causes

Ordered by how often they turn out to be the answer. That ordering is a judgement from experience, not a measured frequency.

A token-computed attribute in a create or generate template

CKA_LOCAL, CKA_ALWAYS_SENSITIVE, CKA_NEVER_EXTRACTABLE, CKA_KEY_GEN_MECHANISM and the unique identifier are set by the token and refused if supplied. The usual way to supply them is to dump an existing object’s attributes and feed the dump back as a template.

Check it: Compare the template against the specification’s list of attributes the token sets. Any of them present is the answer.

Fix: Filter the dump before reusing it. Keep the attributes that describe the object, drop the ones that describe its history.

Changing an identity attribute after creation

Class, key type, the key value, the modulus. These define the object and cannot be altered through a set call on any token. Code that wants a different key has to create one.

Check it: If the failing call is a set, check whether the attribute is one that would change what the object is rather than how it is labelled.

The object was created with modifiable false

A single attribute at creation that locks every other one, including the label and the identifier. Tokens and tooling sometimes default it to false for imported keys, so the object arrives locked without anyone choosing that.

Check it: Read CKA_MODIFIABLE. False means no set call will succeed on this object.

Fix: Recreate the object, or copy it with modifiable true if it is copyable.

Flipping a one-way attribute the wrong way

Sensitive can go from false to true and not back, extractable from true to false and not back, copyable from true to false and not back. A set call in the forbidden direction is refused with this code on most libraries rather than as a bad value.

Check it: Check the direction of the change against the current value.

Which calls return it

C_SetAttributeValue, C_CreateObject, C_CopyObject, C_GenerateKey, C_GenerateKeyPair, C_UnwrapKey

What it is not

It is not a login or session problem. A read-only session refusing a write and a session that is not logged in have their own codes. It is also not an unknown attribute, which is type invalid.

Often confused with

By library

SoftHSMv2

The rules are encoded per attribute from the specification’s footnotes and applied by operation. A non-modifiable object refuses any set, and a trusted certificate is locked the same way ([P11Attributes.cpp](http s://github.com/softhsm/SoftHSMv2/blob/884cb38f3d2012a0447bd5f50dbd29c4 29987c41/src/lib/P11Attributes.cpp#L403-L455)).

IBM opencryptoki

One function decides. Modifiable can be set only at creation and copy, copyable can only ever be turned off, and an attribute outside the function’s list is reported as type invalid rather than read-only (template.c).

OpenSC

Rare, and all in the set-attribute path of the PKCS#15 framework. On a card most attributes are fixed by the card’s file format rather than by policy, so the code says less than it does on a software token.

YubiHSM 2

Never returned. Attribute changes the library does not support are refused as function not supported instead.

Thales Luna

Two native codes map here and one of them is “cannot change key function”. The usage flags on a Luna key, sign, decrypt, wrap and the rest, are locked after creation, and an attempt to change them arrives as this code.

Sources

Every description, cause and check on this page is written from scratch. The specification is cited for the constant's name and its number, which are facts, and for nothing else.