Say when a failed PIN verification tried the default PIN#1075
Open
TicketWindowSeat wants to merge 1 commit into
Open
Say when a failed PIN verification tried the default PIN#1075TicketWindowSeat wants to merge 1 commit into
TicketWindowSeat wants to merge 1 commit into
Conversation
When no PIN is available from pin-value, pin-source or pin-prompt,
New falls back to the YubiKey factory default PIN. If the card uses a
different PIN, every Sign or Decrypt then sends that wrong PIN: each
attempt consumes one of the card's PIN retries and the error
verify pin: smart card error 63c2: verification failed (2 retries remaining)
reads as if the user mistyped a PIN, when it was this package that
chose it. Three such runs block the PIN. This happened in
smallstep/cli#1492, where a pin that did not reach the step-kms-plugin
subprocess ended in a locked YubiKey whose PIV application had to be
reset.
Record in New whether the PIN came from the options or from the
default, and when a PIN verification fails with the default PIN, say
so and name the remedies:
verify pin: smart card error 63c2: verification failed (2 retries
remaining); the YubiKey factory default PIN was tried because no
PIN was available; provide one with pin-value, pin-source or
pin-prompt
The default itself stays documented, intentional behavior; only the
error changes.
Fixes smallstep#1074
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Name of feature:
Bug fix: when a PIN verification fails and the PIN in use was the library's fallback — the YubiKey factory default — the error now says so, and names the URI options that provide the right one.
Pain or issue this feature alleviates:
When no PIN is provided,
Newfalls back to the YubiKey factory default PIN123456(documented, intentional). The trouble is what happens when the card's PIN is not the default:CreateSignerandCreateDecrypterpass the guessed PIN withpiv.PINPolicyAlways, so everySignorDecryptsends aVERIFYwith a wrong PIN. Each attempt consumes one of the card's PIN retries (3 by default), and the error the user sees is:Nothing tells the user the library chose that PIN itself — the error reads like a typo in a PIN they never typed. Retrying the same innocent command twice more blocks the PIN, and a blocked PIN means a PUK ceremony or, as in smallstep/cli#1492, a PIV reset that destroys the PIV keys. In #1492 the user's
pin-valuewas correct but didn't reach thestep-kms-pluginsubprocess; the silent fallback did the rest, and the maintainer confirmed the only way out was a reset. step-kms-plugin#83 shows the same opaque error confusing another user.With this change the same failure reads:
which is self-diagnosing before the last retry is gone. The clause says "no PIN was available" rather than "was provided" deliberately:
uri.Pin()also resolves empty when apin-sourcefile is unreadable or apin-prompthas no terminal, and the message stays true in those cases too.Why is this important to the project (if not answered above):
This library drives an HSM-like device where the failure budget by default is three attempts, and typical CLI usage (
step→step-kms-plugin) spends one process invocation — and therefore one silentVERIFY— per operation. A misconfiguration that costs nothing anywhere else in the KMS surface here consumes an unrecoverable hardware resource. The default-PIN fallback itself is reasonable and stays exactly as documented; the fix is only that failing with a PIN the user never chose now says so.Newrecords whether the PIN came from the options or from the fallback,syncSigner/syncDecryptercarry that flag, and a small helper appends the context when the error matchespiv.AuthErr(which also covers6983: authentication method blocked— the "last retry already gone" case). Errors from an explicitly provided PIN — including an explicitpin-value=123456— are untouched, as is every success path and every non-PIN error.Is there documentation on how to use this feature? If so, where?
No usage change.
New's doc comment now warns that a failed PIN verification consumes one of the card's PIN retries and points atpin-value,pin-sourceandpin-prompt(the prompt option added in #810). The error message itself is the documentation that matters: it names the three URI options at the moment the user needs them.In what environments or workflows is this feature supported?
All platforms the yubikey KMS builds on (build tag
cgo && !noyubikey). The new tests are hardware-free (stubbedpivCards/pivOpen, a failing signer/decrypter injected into the stub) and run in CI: they pin the wrapped message, thaterrors.Is/errors.Asstill reach the original error andpiv.AuthErrthrough the wrap (including the blocked-PINAuthErr{0}case), that no hint appears when a PIN was provided, and that an unreadablepin-sourcefalls back to the default withdefaultPINprovenance recorded. Manually verified on a spare YubiKey 4 (fw 4.3.3, pcsc-lite, 32-bit Linux) with a non-default PIN: the unpatched library burned a real retry with the opaque63c2 ... (2 retries remaining)error; the patched library burned one with the self-diagnosing error (correctly rendering piv-go's singular "1 retry remaining"); a sign with the correctpin-valuethen succeeded and the card reset its retry counter to 3. Full package suite also run on Windows amd64 (CGO_ENABLED=1) and the same 32-bit Linux box. What CI cannot catch: it runs Linux-only with no PC/SC stack or card hardware, so the real VERIFY exchange, the retry-counter decrement, and the end-to-end rendering of this error rest on the manual verification above — the stubbed tests cover everything else.In what environments or workflows is this feature explicitly NOT supported (if any)?
No behavior change: same PINs sent, same operations, same error values (
errors.Is/errors.Ascompatible) — only the message gains a suffix, and only when the fallback PIN was the one that failed. Code that string-matches the exact old error text would see the suffix; error-value comparisons are unaffected.Supporting links/other PRs/issues:
63c2 ... retries remainingerror confusing a user with a non-default PINpin-promptURI option this error now advertisesNew; they are logically independent, and I will rebase whichever lands second.Reviewed and refined with AI assistance; all changes reviewed, run, and verified by me.
💔Thank you!