CRYPTOGRAPHIC TOKENS
What PKCS #11 abstracts, and what it leaves to the token.
An application asks a PKCS #11 module to sign with a key handle. The call succeeds. No private value crosses the interface.
That compact description is one of the standard’s strengths. It is also where many incorrect assumptions begin.
The handle is not the key. It is a temporary reference into a logical object model exposed by a particular Cryptoki library. Behind it may be an HSM cluster, a smart card, a USB token, a remote service or a software implementation. The same function call can reach all of them, but it does not make their policies, failure modes or operational behaviour identical.
PKCS #11 standardises a cryptographic interface. Using it well requires understanding where that abstraction ends.
A portable view, not an identical device
Cryptoki presents applications with slots, tokens, sessions and objects. A slot provides access to a token. A session creates a logical connection to it. Objects represent data, certificates and keys. Mechanisms identify cryptographic operations and their parameters.
This vocabulary lets an application discover capabilities and request operations without speaking a device-specific command protocol. It deliberately hides whether a token has object storage, fixed key positions, several internal partitions or no physical hardware at all.
The mapping is therefore constructive, not merely descriptive. A device with fixed key locations may be presented as a collection of key objects. An HSM cluster may look like one token. A smart card with strict command sequencing may be adapted to a session-oriented API.
Portability exists at the logical boundary. Everything that affects the mapping can still vary:
- which mechanisms are available;
- which parameters a mechanism accepts;
- which attributes can be set or changed;
- how login state is shared across sessions;
- how many concurrent operations are permitted;
- what survives a restart or failover;
- which errors collapse several internal causes into one result;
- which vendor extensions are needed for essential functions.
A portable application cannot assume the intersection of those behaviours is larger than it has tested.
Handles are references, not identities
An object handle is meaningful only within the context in which the module returned it. It should not be stored as the durable identity of a key, passed between unrelated processes or expected to remain stable after the module is reinitialised.
This matters because applications often need two distinct concepts:
- a runtime reference used to perform an operation;
- a durable identifier used to locate the intended object again.
PKCS #11 attributes such as CKA_ID, CKA_LABEL, key type and object class can participate in a search template. None is automatically a globally unique identity. Labels may be duplicated. IDs may be assigned according to a local convention. A certificate, public key and private key may intentionally share an ID so that an application can associate them.
Search therefore needs an explicit naming model. The application should define which attributes establish identity, what uniqueness is expected within a token and what happens when zero or several objects match.
The PKCS #11 URI scheme adds a standard way to describe token and object selection, but it does not eliminate ambiguity in the underlying inventory. A precise URI cannot repair an imprecise provisioning policy.
Attributes are policy, not decoration
A key object is more than key material. Its attributes constrain what the token permits an application to do with it.
For a secret or private key, relevant questions include:
- Can it encrypt, decrypt, sign, verify, wrap, unwrap or derive?
- Is it marked sensitive?
- Is it extractable?
- Was it always sensitive or always non-extractable?
- Which mechanisms may use it?
- Does use require authentication for every operation?
- Can the object be copied, modified or destroyed?
- Is it persistent on the token or limited to one session?
These are not annotations added after key creation. They form part of the key’s effective policy.
Some attributes become read-only once an object exists. Some values are imposed by the token. Some combinations are rejected. Others are silently normalised according to device policy. A template that works on a software token may fail on a certified HSM because the hardware refuses a weaker lifecycle.
An application should treat object creation as policy negotiation with a strict postcondition: after creation, read back every attribute that is observable and verify that the resulting object has the intended capabilities. A successful handle is not sufficient evidence.
Sensitive and non-extractable are different claims
CKA_SENSITIVE and CKA_EXTRACTABLE are frequently compressed into the phrase “the key cannot leave the HSM.” The actual model is more precise.
Sensitivity controls whether secret key material may be revealed through attribute access. Extractability controls whether the key may be exported through a wrapping operation. A non-extractable key should not become extractable later. Historical attributes such as CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE help describe whether those protections have held throughout the object’s lifetime.
Even then, the statement is bounded by the token implementation and its authorised operations. A key that cannot be exported may still be used to decrypt attacker-selected ciphertexts, derive other keys or wrap objects under an inappropriate mechanism. Preventing raw extraction does not make every permitted use safe.
The security boundary is the combination of key attributes, mechanisms, authentication state, application authorisation and token policy.
Generation and import create different histories
Two objects may expose the same attributes today while having different provenance.
A key generated inside the token may never have existed outside its boundary. An imported key necessarily existed elsewhere, at least during provisioning. A key unwrapped inside the token arrived as a protected blob, but its earlier custody depends on the wrapping system and the controls under which the blob was created.
PKCS #11 can express parts of this history through attributes such as whether a key was locally generated. It cannot attest to an entire ceremony by itself.
For meaningful assurance, the application needs an external record of:
- who requested the key;
- which token and partition created or received it;
- which template was applied;
- which wrapping key and mechanism were used;
- which approvals were required;
- whether duplicates or backups exist;
- how the key is to be retired.
The object handle points to current capability. It does not narrate provenance.
Wrapping is a protocol
Key wrapping is sometimes treated as generic encrypted export. In practice it is a protocol between a source token, a destination token and the systems that assign policy on both sides.
The parties must agree on the wrapping mechanism, parameters, key type, transported attributes and destination template. They also need a way to bind the wrapped value to the intended environment and reject substitution or rollback.
Several questions follow:
- Which attributes travel with the wrapped material?
- Which are supplied by the destination application?
- Can the destination weaken the source policy?
- Does the wrapping construction provide integrity as well as confidentiality?
- Can the same blob be replayed into another partition?
- How is the wrapping key rotated without making backups unreadable?
A mechanism that can wrap a key is not automatically a migration design. As with algorithm agility, the difficult part is completing the transition while preserving policy and recoverability.
A mechanism name is not a complete contract
A mechanism identifies an operation, but the surrounding contract may include parameters, input formatting and multi-part behaviour.
With RSA, an application may choose a mechanism that performs raw modular exponentiation, one that applies a signature encoding, or one that performs hashing and encoding inside the token. Those choices determine which bytes cross the interface and which component is responsible for constructing the signed statement.
With ECDSA, implementations may differ in supported curves, signature encoding at the API boundary and treatment of pre-hashed input. With authenticated encryption, parameter structures carry nonces, associated data and tag lengths whose validation can vary between versions and vendors.
Mechanism discovery through C_GetMechanismList and C_GetMechanismInfo is necessary, but it is not a substitute for operation-level tests. A token can advertise a mechanism while rejecting the particular parameter set, key size or object policy the application needs.
The relevant capability is not “supports ECDSA” or “supports AES-GCM.” It is a tested tuple of mechanism, parameters, key attributes, message size, session state and expected output encoding.
Sessions make the interface stateful
Cryptographic operations occur through sessions. A session may be read-only or read/write, public or authenticated, and capable of holding temporary objects and active operation state.
This creates behaviour that is easy to miss behind higher-level language bindings:
- closing a session destroys its session objects;
- login can affect all sessions belonging to an application;
- a single session generally performs only one operation at a time;
- handles from one application are not valid in another;
- module initialisation and finalisation have process-level consequences;
- failover can invalidate sessions and require object rediscovery.
A connection pool for a database and a session pool for an HSM do not have equivalent semantics. The latter carries cryptographic state, authentication state and object visibility rules.
Concurrency should therefore be designed at the PKCS #11 layer rather than left to an incidental wrapper. Each operation needs clear ownership of its session. Recovery needs to distinguish a retryable transport failure from an operation whose completion is unknown.
Errors are part of the boundary
Cryptographic APIs are often evaluated by successful test vectors. Operational reliability depends equally on their failures.
A robust integration should exercise:
- invalid and stale handles;
- removed or unavailable tokens;
- expired authentication state;
- templates with missing, conflicting or forbidden attributes;
- mechanism and parameter mismatches;
- insufficient token memory;
- concurrent use of one session;
- partial multi-part operations;
- failover before and after an irreversible operation;
- vendor-specific return codes.
Retrying every failure is unsafe. A signature request may have completed even if the response was lost. Repeating a key-generation or unwrap operation can create duplicate objects. Reopening a session does not restore the state of an interrupted multi-part operation.
The application needs an error model tied to the semantics of each operation.
Profiles make portability testable
The complete PKCS #11 specification contains more behaviour than most applications or tokens implement. Portability becomes tractable when a deployment defines a narrower profile.
A useful application profile states:
- required PKCS #11 version;
- required mechanisms and parameters;
- supported key types and sizes;
- object templates and naming rules;
- login and session assumptions;
- required attributes and permitted defaults;
- expected encodings;
- concurrency and performance limits;
- backup, failover and recovery behaviour;
- negative tests and accepted error codes.
This profile can be executed against a software token during development and against each target device before deployment. Differences then become explicit compatibility results rather than production surprises.
Software emulation remains useful, but it cannot prove hardware properties. It validates application behaviour at the interface. Claims about tamper resistance, non-exportability and key generation inside a certified boundary require evidence from the actual module and its configuration.
The boundary behind the handle
PKCS #11 succeeds because it gives very different cryptographic devices a common shape. Applications can locate objects, request operations and keep private material behind a defined interface.
The common shape should not be mistaken for identical semantics.
A handle is a reference. An attribute template is a policy request. A mechanism is an operation contract. A session is state. A token is an implementation of a logical boundary whose guarantees still need to be discovered, tested and operated.
The key may remain inside the device. The meaning of using it remains the responsibility of the system outside.



