Documentation wrong about maximum PIN length

The Nitrokey HSM FAQ claims that a PIN may be up to 16 characters long.

Nitrokey PINs can be up to 16 digits long and can consist of numbers, characters and special characters.

Given the hours I wasted wrapping my head around CKR_PIN_LEN_RANGE and CKR_DATA_LEN_RANGE errors led me to believe that this is flat out wrong.

pkcs15-tool -D
Using reader with a card: Nitrokey Nitrokey HSM (…         ) 01 00
PKCS#15 Card […]:
        Version        : 0
        Serial number  : …
        Manufacturer ID: www.CardContact.de
        Flags          : PRN generation


PIN [UserPIN]
        Object Flags   : [0x03], private, modifiable
        Auth ID        : 02
        ID             : 01
        Flags          : [0x812], local, initialized, exchangeRefData
        Length         : min_len:6, max_len:15, stored_len:0
        Pad char       : 0x00
        Reference      : 129 (0x81)
        Type           : ascii-numeric
        Path           : …::
        Tries left     : 3

[…]

This factual error seems to have been around for at least six years.

Please update your documentation or explain how one may use a 16 digit PIN.

Additionally, while not your responsibility, the claims by OpenSC (github -dot- com/OpenSC/OpenSC/wiki/SmartCardHSM#initialize-the-device) that the length of the PIN cannot be changed without reinitialising the device did not help but also appear to be wrong:

Please note that while changing the PIN later is possible, changing its size (length) is not. Current card version 1.2 does not allow this without reinitializing the card.

PS: I get why new users may only use two URLs but ideally it would recognise URLs pointing to your own domains instead of being spam …

1 Like

This is actually a limitation in OpenSC that was introduced to support more PIN PAD readers, most notably Cyberjacks.

Cyberjack PIN PAD readers only support up to 15 digits for the PIN and report an error if more that 15 are requested. As there is no indication on the actual PIN length, the maximum is requested from the reader, as indicated by the card driver.

Our own PKCS#11 module supports up to 16 digits, but only 15 if entered via a PIN PAD. OpenSC unfortunately does not make such a difference.

The device itself perfectly supports 16 digits PINs at the APDU interface. So here is really OpenSC to blame.

1 Like

Thank you for the clarification.

Working in this whole token ecosystem is just a plain horrible experience. Very confusing, inconsistent and incomplete documentation, misleading error messages, tons of tools with lackluster maintenance and similar naming and functionality (e.g. pkcs11-tool vs p11tool). Then suddenly Java and GUIs (SCShell), too. Just terrible if you want to have a robust, reproducible procedure you can trust to work for decades to come, let’s say for an internal root CA.

It’s not just a rant, it is hopefully also seen as a call to action for Nitrokey and others to innovate on HSM management instead of (exclusively) building on the rotten base of historical “standards” (see PIN length). I know I’m not the only one who craves to interface with an HSM with something as easy as a run-of-the-mill REST API.

I’d like to understand what you are trying to achieve.

The whole technology stack you are looking at has grown over time and of course it has a certain learning curve.

If you are simply looking to setup a Root-CA, then I’d suggest to use a tool like XCA, rather than fiddling around with command line tools.

If you want a deep dive into the topic, then you should look at www.smartcard-hsm.com, where we have our own blog posts and links to resources.

It’s also important to understand, that there are two technology layers here: The smart card layer where APDUs are exchanged with the secure element and on top of that the crypto middleware like PKCS#11, CSP, TokenD, Java JCE and others.

Each layer has specific tools and some low level mechanisms can not be mapped to higher layers due to lack of APIs or functions.

This is pretty much the same with larger HSMs. You have the vendor tools for key management and crypto APIs that provide you with a view on the HSM. A REST-API is then nothing more than another view on your keys.

For our own systems we prefer to integrate at the APDU layer with our OpenSCDP scripting environment or Java. That way we have full control on the functionality provided by the SE, but that is of course not portable to other HSMs as this is a proprietary API.

For the SmartCard-HSM my recommendation is to use the Smart Card Shell and the Key Manager for key management and one of the crypto API to integrate with standard software. Using PKCS#11 tools from OpenSC or p11kit will never provide you with the full set of functions. It’s always a limited view on the device.

4 Likes

You handled that well @sc-hsm

My thread was not asking for help but meant to point out the glaring disparity in your documentation. While this may be a limitation of OpenSC unrelated to your hardware your documentation makes regular use of pkcs11-tool which renders the point moot in my opinion.

We wanted to create a key pair for an internal offline root CA, ideally restricting access using an n-of-m scheme without overdoing complexity. That’s all.

We kinda achieved it, using a single DKEK with shared key for backup & restore but key usage still relies on the PIN since handing out NitroKeys to key stewards for public key authentication to use the n-of-m scheme for key usage is overkill for us, regardless of the missing documentation how to actually set it up. No, the slides presenting the mechanics do not really help there. Btw that there is the possibility of multiple DKEK shares (each required) and also a shared key (n-of-m required) for an individual DKEK share is confusing. Not helped by the --total-shares parameter which has different values for creating and importing a DKEK share.

This basically puts the whole misery in one sentence. What I take away from this is that there is no intrinsic motivation to actually improve on the overall system, just putting more abstraction layers on top. Which is really great for a security solution …

My job is to know a lot of tools and dive deep if need be. Meaning I cloned the source code of OpenSC and combed through it to better understand when and why the two error messages mentioned above occurred. My point being: I have seen my share of ecosystems, software and documentation and feel confident in passing judgement. Admittedly anything close to hardware is chronically bad which is why I try to avoid it when possible.

Nice tool but not a fan of most anything built around a GUI for such a use case. Fiddling around with command line tools is preferred for a multitude of reasons and a rather simple approach has been taken. Documentation and configuration is stored in Git. Makes bootstrapping in a disaster recovery scenario much easier.

The fact that NitroKey integrates with standard tools and has its packages available in Debian’s repositories is actually one of the reasons we chose it. Unfortunately some tools like hsmwiz are cleary unmaintained and need manual fixing on Bookworm.

# Modify "engines-1.*" to "engines-*":
/usr/lib/python3/dist-packages/hsmwiz/__main__.py:      "sopath": ':'.join(['/usr/lib'] + glob('/usr/lib/*-gnu*') + glob('/usr/lib/*-gnu*/engines-1.*')),

Note: While not a perfect tool my favourite example for a relatively simple, modern tool compared to e.g. openssl is cfssl: Uses JSON files for configuration/input and is built to be used with pipes.

Thank you but I would like to keep my sanity. It was a close call those last few weeks already. And honestly the fact that the documentation relies on links to blog posts and presentations is a negative in my book.

And the middleware is what I would like to see improved.

Well in my instance I’m not asking for anything outlandish I would assume:

  1. Initialise the device, setting a working PIN and SO-PIN,
  2. Create/import DKEK (that actually worked according to documentation)
  3. Create a private/public key pair (<-- That step cost me a lot of time and headache due to the PIN-length mis-match)
  4. Replicate it to other sticks
  5. Sign a root CA certificate using the key pair

If you got the impression that I would prefer a “larger HSM” I’d like to clarify that my criticism is not specific to Nitrokey. I heard a person working on the first implementation of cloud HSM stuff for AWS was also … not amused about the ecosystem.

Regarding the REST-API: The point here was that instead of a bunch of tools with differing syntax and limitations a single, nice CRUD-style, versioned API would be nice. HTTP is hardly the right technology for a USB device but just to illustrate, that would be a nice workflow:

POST /v1/init PIN=123456;SO-PIN=12345678
POST /v1/import-dkek <payload>
POST /v1/create-key <payload>
GET /v1/wrap-key?id=<id>
GET /v1/wrap-key?label=<label>
POST /v1/unwrap-key?id=<id>
POST /v1/sign <payload>

With some Swagger-like description of all the available API endpoints and expected payloads, required and optional parameters. But yeah, I know, just put some other software on top to handle the mess below, adding that software’s opinionated mess.

But we do not need the device in day-to-day operations. It’s only used to keep the root CA key. It is used every couple of years to sign new issuing intermediate CA certificates which are relatively short-lived and used for ACME for VMs and cert-manager for K8s. For these hardware is not really a good fit since it would bind the programs to certain hosts voiding all that nice distribution for high availability.

Regarding SmartCard Shell specifically:

  1. It has a terrible UX, it’s not obvious how certain things can be achieved, one has to right click on all the items to get an idea what may be possible or sometimes one has to access the menu.
  2. It does not support (fractional) scaling, at least on Wayland systems.
  3. It’s mostly a GUI. Hard to document, prone to changes. No copy & paste of commands. Invites errors due to typos, missing steps, etc.

Closing thoughts:

The best solution for PKI I have come across so far is HashiCorp’s Vault and its fork OpenBao. It also has a steep learning curve but unlike the organically grown mess of the smartcard/HSM ecosystem it actually makes sense with the whole policy system it provides. It has also been doing the n-of-m-scheme basically since the beginning (at the minimum since 2016) and in a very practical way, too. Usage is governed by authorisation via flexible policies not just static authentication. Also it’s possible to perform key rotation e.g. in case of a steward change. Unfortunately it’s also a bit over the top for our needs and resources at the moment and using a backing HSM with Vault requires a very expensive enterprise subscription. My goal remains to use OpenBao without HSM for our issuing CAs in the future.

@kaputt Would you like to have a HashiCorp Vault provider based on your HSM to manage the key domains there instead of smartcard shell?

In case of a long-living, offline root CA no, I don’t think so. HashiCorp Vault is way too complex and - before the relatively recent fork - beholden to a single entity. For this purpose I prefer well-maintained, stable FLOSS tools which are part of most distributions. Which is why Nitrokey relying on such tools is a big plus.

It’s just very frustrating that there is no coherent, streamlined workflow but instead different tools with different limitations, interfaces and gotchas cobbled together. And while there is extensive documentation on some of them that doesn’t mean it’s good. And a “gotcha” in the documentation is the grievance which lead to this thread.