Skip to content

Instantly share code, notes, and snippets.

@bettse
Created February 21, 2026 19:38
Show Gist options
  • Select an option

  • Save bettse/ef677ed80553d43e2e767986241723c0 to your computer and use it in GitHub Desktop.

Select an option

Save bettse/ef677ed80553d43e2e767986241723c0 to your computer and use it in GitHub Desktop.

GlobalPlatform and Secure Channel Analysis

Date: 2026-02-21
Project: HidGlobal.UniversalEncoder.Stubs.ConfigCardProgrammer


Q: Are there any references to GP/GlobalPlatform?

Yes, there are several references:

Project References

  • Assembly: HidGlobal.Smartcard.GlobalPlatform.dll referenced in the .csproj file
  • Namespace: using HidGlobal.Smartcard.GlobalPlatform; in ConfigCardProgrammer.cs

CLA.GP Usage

Four instances in ConfigCardProgrammer.cs use CLA.GP in APDU commands:

  • Line 382: DELETE command
  • Line 402: INSTALL [for load] command
  • Line 425: LOAD command
  • Line 464: INSTALL [for install] command

The code uses GlobalPlatform for smartcard operations, specifically for managing applets on the card.


Q: Is INIT UPDATE used?

No, INIT UPDATE is not explicitly used in this code.

The code uses OpenSecureChannel() method instead, which is a higher-level abstraction that likely handles the GlobalPlatform secure channel initialization internally (possibly including INITIALIZE UPDATE and EXTERNAL AUTHENTICATE commands under the hood).

The implementation delegates to method_0() which sends commands to the SAM/interpreter rather than directly executing GP APDU commands.


Q: What triggers the use of OpenSecureChannel? Can it be avoided?

When OpenSecureChannel is Called

OpenSecureChannel() is triggered in 5 scenarios:

  1. PersonalizeMedia(SNMPKeyRollerCardParameters) - Line 241
  2. LoadUpdaterApplet() - Line 470 (with SecurityLevel.MacEncrypt)
  3. After transport key injection - Line 511 (with SecurityLevel.MacEncrypt)
  4. PersonalizeMedia(AppLoaderCardParameters) - Line 530
  5. PersonalizeMedia(ConfigCardParameters) - Line 593

Can it be Avoided?

Probably not for most operations. Looking at the code:

  1. The GP commands (Delete, Install, Load) use a SecurityLevel parameter, and when it's SecurityLevel.MacEncrypt or SecurityLevel.Mac, secure channel is required.

  2. The secure channel appears mandatory for:

    • Loading/deleting applets (GlobalPlatform operations require authentication)
    • Personalizing cards (all 3 PersonalizeMedia methods call it)
    • Injecting keys (sensitive operations)
  3. The only way to potentially avoid it would be to use SecurityLevel.Clear, but the code checks securityLevel_0 != SecurityLevel.Clear - suggesting clear mode might be supported for some operations, but it's never actually used in the public methods (they all hardcode SecurityLevel.MacEncrypt).


Q: Tell me more about method_11 and the SecurityLevel parameter

SecurityLevel Enum

From HidGlobal.Smartcard.GlobalPlatform.SecurityLevel.cs:

public enum SecurityLevel : byte
{
    Clear = 0,
    Mac = 1,
    MacEncrypt = 3,
}

method_11 Behavior

private void method_11(CommandAPDU commandAPDU_0, bool bool_1)
{
    string hexString = commandAPDU_0.ToHexString();
    this.method_0(Util.HexStringToByteArray(
        (bool_1 ? (byte) 28 : (byte) 23).ToString("X2") + 
        (hexString.Length / 2).ToString("X4") + 
        hexString));
}

Key Insight

The boolean parameter determines the command code sent to the interpreter:

  • bool_1 = false → Command code 0x17 (23) - Send APDU without secure channel
  • bool_1 = true → Command code 0x1C (28) - Send APDU over secure channel

How SecurityLevel is Converted to Boolean

// Line 382:
securityLevel_0 != SecurityLevel.Clear

// Line 388:
bool_1 = securityLevel_0 != SecurityLevel.Clear

So if SecurityLevel.Clear is used, the boolean becomes false and command 0x17 is used (no secure channel).

Can Secure Channel Be Avoided?

Yes, by passing SecurityLevel.Clear to methods like DeleteInstance() or DeleteCAP(), but the public PersonalizeMedia() and LoadUpdaterApplet() methods hardcode SecurityLevel.MacEncrypt, so you'd need to modify the code or add new methods that accept SecurityLevel as a parameter.


Q: Tell me more about PersonalizeMedia

There are 3 overloaded PersonalizeMedia methods for different card types:

1. PersonalizeMedia(SNMPKeyRollerCardParameters) - Lines 225-260

Purpose: Programs SNMP Key Roller cards for key management

Process:

  1. Validates parameters (current/new auth & privacy keys, ICE number)
  2. Selects Key Roller card (command 0x13)
  3. Checks applet version compatibility
  4. Opens secure channel (line 241)
  5. Writes ICE number based on authentication algorithm (commands 0x0D)
  6. Writes current SNMP keys (commands 0x08, 0x09)
  7. Writes new SNMP keys (commands 0x0B, 0x0C)
  8. Finalizes (command 0x10)

Parameters:

  • Current/New SNMP Authentication & Privacy keys (OIDs)
  • ICE Number (identifier)
  • NumberOfReaders

2. PersonalizeMedia(AppLoaderCardParameters) - Lines 516-558

Purpose: Programs AppLoader cards with .NET assemblies

Process:

  1. Validates SNMP keys and assemblies
  2. Selects AppLoader card (command 0x15)
  3. Checks applet version compatibility
  4. Opens secure channel (line 530)
  5. Loads each assembly in 128-byte chunks (command 0x21)
  6. Writes assembly metadata (commands 0x22, 0x23, 0x24)
  7. Writes SNMP keys (commands 0x08, 0x09)
  8. Finalizes (command 0x10)

Parameters:

  • SNMP Authentication & Privacy keys
  • List of assembly paths
  • NumberOfReaders
  • SAMFirmwareId

3. PersonalizeMedia(ConfigCardParameters) - Lines 560-624

Purpose: Programs Configuration cards with config items and key references

Process:

  1. Validates SNMP keys
  2. Selects Config card (command 0x12)
  3. Checks applet version compatibility
  4. Converts KeyConfigurationItems to KeyReferenceConfigurationItems
  5. Validates at least one item exists
  6. Calculates sizes
  7. Opens secure channel (line 593)
  8. Writes SNMP keys (commands 0x08, 0x09)
  9. Writes key configuration OIDs (command 0x04)
  10. Writes configuration values (command 0x05)
  11. Finalizes with metadata (command 0x07)
  12. Writes final OIDs (command 0x06)
  13. Finalizes (command 0x10)

Parameters:

  • ConfigurationItems (list of config data)
  • KeyConfigurationItems (list of key references)
  • SNMP Authentication & Privacy keys
  • NumberOfReaders

Common Pattern

All three methods hardcode secure channel usage - they all call OpenSecureChannel() without a SecurityLevel parameter (defaults to MacEncrypt). There's no public API to bypass secure channel for personalization operations.


Q: Does the PersonalizeMedia code check if the secure channel is open and use different commands based on its presence?

No, PersonalizeMedia does NOT check if the secure channel is open. Looking at all three implementations:

  1. All three unconditionally call OpenSecureChannel() (lines 241, 530, 593)
  2. All subsequent commands use method_0() which sends interpreter commands to the SAM
  3. None of them use method_11() or method_10() which would take a boolean to indicate secure channel usage

Key Insight: Different Command Pathway

PersonalizeMedia uses a different command pathway:

  • method_0() - Sends commands directly to the interpreter on the SAM (not direct APDUs to the card)
  • method_11() - Sends APDUs with conditional secure channel (command 0x17 vs 0x1C)

After OpenSecureChannel(), the PersonalizeMedia methods send interpreter commands (0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x0D, 0x10, 0x11, 0x13, 0x15, etc.) that are handled by the SAM's interpreter, which presumably manages the secure channel state internally.

The secure channel state is maintained on the SAM side, not explicitly checked in the code. Once OpenSecureChannel() (command 0x19) is called, subsequent interpreter commands automatically use the established secure channel until ResetSecureChannel() (command 0x1A) is called.

Answer: No conditional logic exists - the code assumes secure channel is required and always establishes it before sending personalization commands.


Q: When are method_10 or method_11 used?

method_10 and method_11 are used exclusively for GlobalPlatform card management operations - they send raw APDUs directly to the card (not through the SAM interpreter).

method_10 Usage (always WITHOUT secure channel)

Line 469: LoadUpdaterApplet() - Selects the GlobalPlatform Security Domain

this.method_10(new CommandAPDU(CLA.ISO, INS.SelectByAid, P1.SelectByAid, P2.Null, 
    SecurityDomain.DEFAULT_OPEN_SECURITYDOMAIN_AID));

method_11 Usage (conditionally uses secure channel)

1. Lines 346, 350 - method_13() - Sends PUT DATA commands (CLA 0xA0, INS 0xDA)

  • Called from method_12() which is used by AppLoader personalization
  • Chunks large data into 255-byte blocks

2. Line 382 - method_14() - GP DELETE command

  • Used by DeleteInstance() and DeleteCAP()
  • securityLevel_0 != SecurityLevel.Clear determines if secure channel is used

3. Line 402 - method_15() - GP INSTALL [for load] command

  • Loads CAP file metadata
  • Used by LoadUpdaterApplet()

4. Line 425 - method_15() - GP LOAD command

  • Loads CAP file binary data in chunks
  • Used by LoadUpdaterApplet()

5. Line 464 - method_17() - GP INSTALL [for install and make selectable] command

  • Creates applet instance
  • Used by LoadUpdaterApplet()

Summary Table

Method Purpose Secure Channel When Used
method_10 Send APDU without secure channel Never (always 0x17) SELECT AID before opening secure channel
method_11 Send APDU conditionally with secure channel Based on bool parameter GlobalPlatform operations (DELETE, INSTALL, LOAD, PUT DATA)

Key Pattern

  • method_10/11 = Direct card communication for GlobalPlatform operations (applet management)
  • method_0 = SAM interpreter commands for personalization operations (writing config data)

The code uses GlobalPlatform APDUs when managing applet lifecycle (load/delete/install), but uses SAM interpreter commands when personalizing card content.


Q: When is LoadUpdaterApplet called?

Called by: ConfigCardHelper.UpdateJcopCardIfRequired() in the HID.UniversalProgrammer.Core assembly

Scenario 1: Card Selection Fails (Line 66)

When trying to select the card applet (ConfigCard or KeyRollerCard) and it throws an exception (applet doesn't exist):

try {
    if (isElitePrepCard)
        configCardProgrammer.SelectKeyRollerCard();
    else
        configCardProgrammer.SelectConfigCard();
}
catch {
    // Applet not found - load it
    configCardProgrammer.LoadUpdaterApplet(
        isElitePrepCard ? UpdaterInstanceType.SNMPKeyRoll : UpdaterInstanceType.Config);
}

Scenario 2: Applet Version is Outdated (Line 81)

When RequiresAppletReloading() returns true (applet version < 3.3):

if (!configCardProgrammer.RequiresAppletReloading())
    return JCopCardUpdateResult.NoUpdateRequired;

// Applet needs updating
configCardProgrammer.LoadUpdaterApplet(
    isElitePrepCard ? UpdaterInstanceType.SNMPKeyRoll : UpdaterInstanceType.Config);

What LoadUpdaterApplet Does

  1. Selects GlobalPlatform Security Domain (using method_10 - no secure channel)
  2. Opens secure channel with SecurityLevel.MacEncrypt
  3. Deletes old applet instances (if they exist) using GP DELETE commands
  4. Loads new CAP file using GP INSTALL [for load] and LOAD commands
  5. Installs applet instance using GP INSTALL [for install]
  6. Selects the newly installed applet
  7. Opens secure channel again
  8. Injects transport/wrapping key (command 0x1B)

Purpose: This is a card provisioning/update operation that uses standard GlobalPlatform commands to manage JavaCard applets on the JCOP card. It's called when the card is blank or has an outdated applet version, before any personalization can occur.


Q: When is UpdateJcopCardIfRequired called?

UpdateJcopCardIfRequired() is called by:

1. ConfigCardGenerator.GenerateCard() (Line 83)

Purpose: Creates configuration cards for programming readers

When called: During config card generation workflow

  • isElitePrepCard = false (regular config card)
  • Called after SAM authentication
  • Before personalizing the card with configuration data

Workflow:

public CardProgrammingResult GenerateCard(IDataManager dataManager, int NumberOfCredits)
{
    SamAuthentication.SetCurrentReader(dataManager.SamAuthManager, this._readerName);
    if (!SamAuthentication.CurrentSam.Authenticate())
        return CardProgrammingResult.UnknownError;
    
    // Check/update JCOP applet first
    switch (ConfigCardHelper.UpdateJcopCardIfRequired(this._readerName, false))
    {
        case JCopCardUpdateResult.UpdateFailed:
            return CardProgrammingResult.JcopAppletUploadError;
        case JCopCardUpdateResult.NoCardOnReader:
            return CardProgrammingResult.CardNotOnReader;
        case JCopCardUpdateResult.SecureChannelError:
            return CardProgrammingResult.SecureChannelError;
        default:
            // Continue with programming...
            configCardProgrammer.PersonalizeMedia(parameters);
    }
}

2. ElitePrepCardGenerator.GenerateCard() (Line 37)

Purpose: Creates SNMP key roller cards (Elite Prep Cards)

When called: During Elite Prep card generation workflow

  • isElitePrepCard = true (SNMP key roller card)
  • Called after SAM authentication
  • Before personalizing with SNMP key rolling parameters

Workflow:

public CardProgrammingResult GenerateCard(
    IDataManager dataManager,
    string currentSnmpConfig,
    string newSnmpConfig,
    int NumberOfCredits)
{
    SamAuthentication.SetCurrentReader(dataManager.SamAuthManager, this._readerName);
    if (!SamAuthentication.CurrentSam.Authenticate())
        return CardProgrammingResult.UnknownError;
    
    // Check/update JCOP applet first
    switch (ConfigCardHelper.UpdateJcopCardIfRequired(this._readerName, true))
    {
        case JCopCardUpdateResult.UpdateFailed:
            return CardProgrammingResult.JcopAppletUploadError;
        case JCopCardUpdateResult.NoCardOnReader:
            return CardProgrammingResult.CardNotOnReader;
        default:
            // Continue with programming...
            configCardProgrammer.PersonalizeMedia(snmpKeyRollerParameters);
    }
}

Summary

UpdateJcopCardIfRequired() is called at the beginning of card generation workflows as a prerequisite check to ensure:

  1. The card has the correct JCOP applet loaded
  2. The applet is the current version (≥ 3.3)
  3. The card is ready for personalization

It acts as a card preparation step before any PersonalizeMedia() operations, ensuring the card firmware/applet is compatible with the programming operations that follow.


Architecture Summary

Two-Level Command Architecture

  1. GlobalPlatform Operations (via method_10/method_11)

    • Direct APDU communication to card
    • Used for applet lifecycle management (load/install/delete)
    • Supports conditional secure channel (SecurityLevel.Clear, Mac, MacEncrypt)
    • Command codes: 0x17 (no secure channel), 0x1C (with secure channel)
  2. SAM Interpreter Operations (via method_0)

    • High-level commands to SAM interpreter
    • Used for card personalization (writing config data, keys)
    • Secure channel managed internally by SAM
    • Requires prior OpenSecureChannel() call (command 0x19)

Secure Channel Flow

Card Generation Workflow
    ↓
UpdateJcopCardIfRequired()
    ↓ (if needed)
LoadUpdaterApplet()
    → SELECT Security Domain (method_10, no SC)
    → OpenSecureChannel(MacEncrypt)
    → GP DELETE/INSTALL/LOAD (method_11, with SC)
    ↓
PersonalizeMedia()
    → Select card type applet
    → OpenSecureChannel() (command 0x19 via method_0)
    → Write data (commands 0x04-0x10 via method_0)
    → All subsequent commands use established SC

Key Finding

GlobalPlatform INITIALIZE UPDATE is abstracted away - the OpenSecureChannel() method sends command 0x19 to the SAM interpreter, which handles the actual GP secure channel establishment (INITIALIZE UPDATE + EXTERNAL AUTHENTICATE) internally. The application code never directly sends these GP commands.

Comments are disabled for this gist.