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
CKR_SESSION_READ_ONLY: The session-level refusal to write. This code is about the attribute or object, that one is about the session.CKR_ATTRIBUTE_TYPE_INVALID: Unknown attribute versus known attribute you may not set.CKR_ATTRIBUTE_VALUE_INVALID: Where some libraries put a one-way attribute flipped the wrong direction.
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
- PKCS #11 Specification Version 3.2, OASIS. Read 2026-09-10. Used for constant name and numeric value.
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.