Skip to content
Oclavex is in private preview, available to selected users. Public signup is blocked. Request access at [email protected].

Hardware keys (YubiKey)

A license that requires a YubiKey activates only with a key generated inside a genuine YubiKey 5, and then works only on a computer where that YubiKey is plugged in. The customer can move the license from one computer to another by moving the key, online or offline, and the license file itself needs no protection.

Your application uses the SDK’s hardware-key add-on. On the customer’s YubiKey it creates one key of its own in a free retired slot, and never touches the customer’s other keys. That key’s thumbprint is the device fingerprint the license is bound to.

At activation the application sends the YubiKey’s attestation with the request. The attestation is a certificate chain that Yubico’s own certificates sign; it proves the key was generated inside a genuine YubiKey and cannot be copied out of it. Oclavex checks it before the license is issued:

  • the chain leads to Yubico’s published attestation certificates, with a Yubico CA directly above the YubiKey’s own attestation certificate;
  • the key is a P-256 key on firmware 5.7 or later;
  • the key’s thumbprint is the fingerprint the device activates with;
  • the key asks for a touch before every signature, when the license requires one.

An attestation is public: anyone who has seen it could send it again. So every online activation also proves the YubiKey is present right then: the application asks Oclavex for a fresh nonce, and the YubiKey’s key signs it (RFC 9449 DPoP). Oclavex accepts only a signature by the attested key, for that request, over a nonce it issued in the last two minutes.

A license that requires a YubiKey refuses any activation without this proof, online and offline. Devices activated before the requirement was turned on keep their licenses until their sessions are released or revoked.

When the application starts, the YubiKey signs a fresh challenge before the license is used. A copied license file, or the same fingerprint on a computer without the YubiKey, fails that check. Your application can repeat the check at any time, for example to notice that the key was unplugged.

Everything is on the entitlement’s or the offer’s Policies tab. An offer hands its settings to every entitlement made from it.

  1. Turn on Require a YubiKey to activate. Turn on Require a touch on the YubiKey too if a person must be at the computer whenever the key signs.
  2. Choose who may activate, on the Activation policy card. An application that activates without signing anyone in, like the example below, needs Activation security level set to Anonymous. The default, Identify (log in), needs a signed-in user. If your application signs its user in, keep the default and use interactive-user activation.
  3. On the Activation codes tab, create the code your customer enters. For an application that activates without signing in, choose Any User under Who can access the license; the dialog offers it only when the activation security level is Anonymous. A code that needs a signed-in user refuses such an application with license.authentication_required and requires: sign_in. A code you created earlier shows its choice as Authentication requirement; set it to Anonymous / Any User.

Your application also needs your Oclavex address, such as https://acme.oclavex.com, and your license-signing public key: in Settings → License signing keys, choose Copy public key on the key’s row. See the provider key is mandatory.

  • A YubiKey 5 series key with firmware 5.7 or later. Older firmware leaks elliptic-curve keys to someone with physical access and specialized equipment (YSA-2024-03), so it is not used.
  • Windows or macOS need no driver. Linux needs the pcscd smart-card service.
  • No PIN and no setup on the YubiKey: the application creates its key on the first start. A YubiKey whose PIV management key was changed, as company-issued keys often are, needs that management key once, for that first start.

Add the add-on beside the SDK:

Terminal window
dotnet add package Revenusion.Oclavex.Client.HardwareKeys

Then make the YubiKey the device fingerprint. The name you pass labels the key on the YubiKey, so use your company or product name. This example asks for the YubiKey when none is plugged in:

using Revenusion.Oclavex.Client.AspNetCore;
using Revenusion.Oclavex.Client.LicenseConsumer;
using Revenusion.Oclavex.HttpConnector;
var yubiKey = new YubiKeyNodeId("Acme Tools");
var check = yubiKey.Check();
while (check.Exception is YubiKeyException { Failure: YubiKeyFailure.NoKey })
{
Console.WriteLine("Insert your YubiKey, then press Enter.");
Console.ReadLine();
check = yubiKey.Check();
}
if (!check.IsSuccess)
{
Console.WriteLine(check.Exception?.Message);
return;
}
await using var session = new LicenseClientBuilder()
.UsePublicKey(publicKey)
.UseLicenseKey(StaticLicenseKeyProvider.Create(activationCode))
.UseNodeId(yubiKey)
.UseOclavexHttpClient(OclavexClientFactory.Create(tenantUrl, new AnonymousAuthentication()))
.BuildSession();
var access = await session.AccessLicenseAsync();

Check() has the key sign a fresh challenge. The first check on a YubiKey creates the key; from then on the application finds the key by its label, and every activation goes to Oclavex with the key’s attestation.

Call yubiKey.Check() again whenever you want to know the key is still plugged in, for example before a licensed feature runs. It succeeds only for that same key; another YubiKey fails it.

Without a prompt of your own, .UseYubiKey("Acme Tools") on the builder replaces the YubiKeyNodeId and the checks. BuildSession then throws a YubiKeyException when no YubiKey is plugged in.

When the license requires a touch, create the key with a touch policy: new YubiKeyNodeId("Acme Tools", new YubiKeyOptions { TouchPolicy = YubiKeyTouchPolicy.Always }). The key then signs only after a touch, and a check that gets no touch within 15 seconds fails with an OperationCanceledException. Every online activation, lease refreshes included, signs its proof of possession too, so it needs a touch of its own. The touch policy is fixed when the key is created. A key created without one is refused by a license that requires a touch; remove it with Clear(), and the next start creates a new one.

  • It creates a P-256 key in the highest free retired PIV slot, 95 down to 82, and labels it CN=Oclavex license key, O=<your name>. The slots 9A, 9C, 9D and 9E, and every slot it did not label, are never touched.
  • Checks need neither the PIN nor the management key. Creating and removing the key need the PIV management key: the factory default is tried once. Pass a changed management key in YubiKeyOptions.ManagementKey.
  • yubiKey.Clear() removes your key and its label, for example when the customer uninstalls. A license bound to that key stops working.

A refused activation comes back as a failed result. Branch on its ErrorCodeName:

ErrorCodeName Code What happened
hardware_key.attestation_refused 7001 The attestation did not hold: not a genuine YubiKey 5, firmware older than 5.7, or a different key.
hardware_key.proof_refused 7002 The proof that the YubiKey is present did not hold: not signed by the attested key, made for another request, or its nonce expired.
license.hardware_keys_not_licensed 2023 Your Oclavex plan doesn’t include hardware keys.
license.forbidden_by_policy 2011 The license’s policy refused it, for example a license that requires a touch while the key was set up without one.
license.authentication_required 2028 The activation code needs a signed-in user or a confirmed email, and the application activated without one (HTTP 401). See set up the license.

When the refusal was for something missing, the result’s Requires says what, so your application can act on it: ActivationRequirements.SignIn, HardwareKey or HardwareKeyTouch, for example. The error codes page lists every value.

An application built without the add-on cannot activate a license that requires a YubiKey: it is refused with license.forbidden_by_policy.

When the YubiKey can’t be used, nothing is sent, and the result’s Exception is a YubiKeyException. Its Failure says why:

Failure What happened
NoKey No YubiKey is plugged in.
FirmwareNotSupported The YubiKey’s firmware is older than 5.7.
NotEnrolled The YubiKey holds no key for your name, or not the key the application is bound to.
WrongKey The YubiKey holds a key for your name, but not the one the license is bound to.
SeveralKeys More than one plugged-in YubiKey qualifies. Leave only one plugged in.
ManagementKeyRefused The YubiKey refused the management key. Pass the customer’s in YubiKeyOptions.ManagementKey.
NoFreeSlot All retired slots, 82 to 95, hold other keys.
ChallengeFailed The key’s signature did not verify with its own public key.
DeviceError The YubiKey stopped answering, for example because it was unplugged.

An air-gapped device’s request file carries the attestation too. Upload it on the Provision portal’s Offline activation page as usual: the portal sees the attestation and has it checked before the response is signed. The signed response imports only on a computer where the same YubiKey is plugged in.

  • The check runs in your application. A patched application can skip it; Oclavex does not wrap or encrypt executables. Online activation still needs the YubiKey, because Oclavex checks the proof of possession itself.
  • Offline requests carry no proof of possession. Your operator uploads them, often much later, so there is no fresh nonce to sign. The attestation shows the key was made in a genuine YubiKey.
  • Relayed challenges. One YubiKey could answer challenges relayed from several computers over a network. They all carry the key’s fingerprint, so they count as one device.
  • Virtual machines. A cloned virtual machine has no key. Several instances on one host can share one plugged-in key; limit them with seats.
  • A deleted key cannot be restored. Any program on the computer can delete the key, but none can copy it. Setting the key up again and re-issuing the license recovers.
  • YubiKey 5 series with firmware 5.7 or later. Older firmware, the Security Key series and other brands are not accepted.