Skip to content

PIN Code

The PIN code serves as the primary authentication mechanism for the hardware wallet card in this non-custodial solution. It ensures that sensitive operations are authorized by the cardholder, protecting the private keys stored on the secure element.

2. Purpose

The PIN code is required for:

  • Authorization: Unlocking the card to perform cryptographic operations (e.g., signing transactions).
  • Security: Acting as a knowledge factor to prevent unauthorized usage if the physical card is lost or stolen.
  • Management: Authorizing administrative tasks, specifically changing the PIN code itself (CmdSetPin).

3. PIN Length Specifications

The system supports configurable PIN lengths, with the following constraints observed in the Settings.vue implementation:

  • Default Length: 4 digits.
  • Minimum Length: 4 digits (enforced by UI validation).
  • Maximum Length: 8 digits.

4. How It Is Sent to the Card

The PIN is not stored in the application; it is sent directly to the card during an NFC or FIDO session to authorize a command.

  1. Preparation: The application collects the PIN (and "Old PIN" if changing it) from the user.
  2. Request Building: The CmdSetPin class constructs a request object containing the PIN data and card keys.
  3. Transmission: An NFC handler (nfcProgressHandler) establishes a session with the card and transmits the prepared command.

5. Functions & Implementation

The core logic is found in src/pages/Settings.vue and relies on the API handler @/api/card-io.

Key Functions

CmdSetPin.buildRequest(data)

Constructs the payload required to instruct the card to update its PIN.

  • Input: Object containing keys (public key info), oldPin, and newPin.
  • Output: A request object ready for transmission.

nfcProgressHandler(request, CommandClass, isMassOperation)

Manages the physical communication layer (NFC/FIDO). It takes the request built by CmdSetPin and executes it against the card.

confirmPinHandler (in Settings.vue)

The UI controller method that orchestrates the flow:

  1. Validates pinOld and pinNew.
  2. Sets the IO settings (setUniSettings).
  3. Calls buildRequest.
  4. Invokes the NFC handler.

6. Usage Example

Below is a technical example demonstrating how to programmatically construct a request to change the PIN, mirroring the logic in Settings.vue.

javascript
import { CmdSetPin } from '@/api/card-io';
import { setUniSettings } from '@/api/global-settings';

/**
 * Changes the PIN code on the card.
 * 
 * @param {Object} publicKeyCard - The card's public key object (store.state.user.publicKeyCard).
 * @param {String} oldPin - The current PIN code.
 * @param {String} newPin - The new PIN code.
 * @param {Object} nfcHandlerWindow - Reference to the NFC Handler component.
 */
async function changeCardPin(publicKeyCard, oldPin, newPin, nfcHandlerWindow) {
  // 1. Prepare the data payload
  const pinPrepareData = {
    "keys": publicKeyCard,
    "oldPin": oldPin,
    "newPin": newPin
  };

  // 2. Configure IO settings (e.g., 'nfc' or 'fido')
  // This ensures the correct reader protocol is used.
  setUniSettings({ ioMethod: 'nfc' });

  try {
    // 3. Build the Request
    // This prepares the APDU or command structure expected by the card firmware.
    const requestPayload = await CmdSetPin.buildRequest(pinPrepareData);

    // 4. Execute via NFC Handler
    // This opens the NFC modal and waits for the user to tap the card.
    const result = await nfcHandlerWindow.nfcProgressHandler(requestPayload, CmdSetPin, false);
    
    return result;
  } catch (error) {
    console.error("Failed to change PIN:", error);
    throw error;
  }
}