SecureSign — DSC Signing Flow Reference
Seven stages of a signing operation, compared across today's hardware-token desktop DSC signing, today's software-only (soft-cert) DSC signing, PC test tools, the mobile app, the STM32F417 prototype, and the STM32U585 + FPGA production target.
| Stage | What Happens | Today — Hardware Token (Desktop) | Today — Software-Based DSC (No Hardware) | Windows / Mac (PC Test) | Mobile App | Prototype (F417 + mbedTLS) | Real Hardware (U585 + FPGA) | Touches Controller? |
|---|---|---|---|---|---|---|---|---|
| 0. Onboarding — key generation | Device generates a key pair internally; only the public key ever leaves. | Done once, at purchase, by the DSC vendor (eMudhra, Sify, Capricorn, etc.) — usually at a physical Registration Authority or via video-KYC, per CCA rules. Key pair generated on-token by the vendor's own provisioning tools before delivery. | Key pair generated in software (e.g. OpenSSL, or the CA's own enrollment tool) and exported into a password-protected PKCS#12 (.pfx) file. Unlike a hardware token, the private key is exportable — it exists as a file, not confined to a chip. |
N/A for the six-step test below. | SDK calls generateKeyPair() once during enrollment. |
Skipped — demo key pair pre-embedded in flash at build time. | Real GENERATE_KEY_PAIR APDU; key pair generated inside the FPGA's secure key store. |
Yes (real HW) N/A (prototype) |
| 1. Plug in / enumerate | OS recognizes the dongle as a standard USB smart-card reader. | User plugs a USB-A token into a PC. Almost always requires installing that specific vendor's own proprietary driver/middleware first (ePass2003, Aladdin eToken, Watchdata, etc.) — a different installer per brand, and none of it works on mobile. This is the actual gap SecureSign is solving. | Nothing to plug in — the .pfx file just needs to be present on disk (or copied/emailed between machines, which is itself a real security weakness this approach has and hardware tokens don't). |
Device Manager shows a generic "Smart card readers" entry automatically — standard usbccid.sys, no driver install. |
Android: USB Host API attach intent. iOS: needs MFi certification. | STM32F417 enumerates as composite CDC + CCID. | Same enumeration; crypto backend behind it doesn't change this step. | Yes |
| 2. Power on / get ATR | Host asks "what card is this," device answers with its ATR. | Handled invisibly by the vendor's PKCS#11 DLL/driver stack, hidden behind whatever signer utility (or historically, Java applet) the portal uses. | N/A — no smart-card protocol involved. The signing app simply opens the .pfx file directly, using a standard crypto library (e.g. Windows CryptoAPI, OpenSSL). |
opensc-tool --atr / certutil -scinfo |
SDK/middleware issues the equivalent low-level open-session call. | SC_Itf_IccPowerOn() returns a placeholder ATR (still not a real card's ATR — only enough to enumerate; the rest of the flow below no longer needs it to be more than that). |
Forwarded to FPGA over SPI, returns its real capability info. | Yes |
| 3. Read certificates | Host reads the token's cert(s) via SELECT + READ BINARY APDUs. | Signer utility/browser plugin calls the vendor's own PKCS#11 DLL to enumerate certs — works, but only with that vendor's software installed. | The signing app reads the certificate bundled inside the .pfx file itself — a local file parse, not a device query. |
pkcs15-tool --list-certificates |
SDK's enumerateCertificates() → PKCS#11 C_FindObjects/C_GetAttributeValue |
Real SELECT + READ BINARY against a PKCS#15 file system in flash (EF(ODF)/AODF/PrKDF/CDF + the cert EF), with GET RESPONSE chaining since the demo cert (611 B DER) is larger than one CCID bulk message. Same wire protocol a real card uses, not a shortcut. | Same APDUs; cert from secure NVM on the FPGA side. | Yes |
| 4. PIN verification | User's PIN is checked against the device, never cached elsewhere. | Desktop popup (native OS dialog or the signer utility's own window) asks for the token PIN, forwards it to the vendor stack. | User enters a password/passphrase that decrypts the .pfx locally. Critically, this decrypts the private key into the application's own memory — unlike a hardware token, where the key never leaves the chip at all. |
pkcs11-tool --login --pin 1234 |
User enters PIN in-app → SDK's authenticate(pin) → C_Login → VERIFY APDU |
Real VERIFY APDU (INS 0x20) against the demo PIN, with a 3-try RAM retry counter and the standard 63Cx "X tries left" / 6983 "blocked" status words — same host-visible behavior as a real card, just checked against a flash-embedded demo value instead of provisioned secret storage. |
PIN check happens inside FPGA's secure boundary, not the MCU. | Yes — comparison happens on-controller |
| 5. Sign document | App hashes the document, sends only the hash; device signs it with the private key. | Desktop signer utility (or historically a Java applet) hashes the document, sends it via vendor PKCS#11, gets the signature back, embeds it — same PAdES/XMLDSig standards as the new solution. | The hash is signed using the private key now sitting in the app's RAM, via software crypto (e.g. OpenSSL) on the general-purpose PC. The actual signing operation happens outside any tamper-resistant hardware — this is the core difference from both the hardware token and SecureSign. | pkcs11-tool --sign --mechanism ECDSA-SHA256 |
SDK's signHash()/signPdf()/signXml() → C_Sign → PSO APDU |
Real PSO: COMPUTE DIGITAL SIGNATURE APDU (INS 0x2A, P1P2 9E9A), gated on PIN verification, signs the host-supplied hash via mbedtls_ecdsa_sign_det() (deterministic ECDSA / RFC 6979 — no RNG dependency) and returns raw r‖s — software crypto on the F417, not certified, prototype only. |
FPGA's ECC engine signs; key never leaves it; signature relayed back through STM32U585. | Yes — core security-critical step |
| 6. Verify signature | Anyone checks the signature against the public certificate. | Identical to the new solution — recipient verifies with the public certificate, independent of desktop vs. mobile vs. any vendor. | Identical again — verification only ever needs the public certificate, regardless of how (or how insecurely) the private key was held during signing. | openssl dgst -verify pub.pem -signature test.sig test.txt |
Optional in-app convenience, or left to the recipient. | N/A — pure math. | N/A — pure math, identical regardless of backend. | No — device never touched again |
pkcs15-tool/pkcs11-tool recognizing the card on the first flash isn't guaranteed — the raw-APDU
path (opensc-tool --send-apdu) is the reliable fallback for proving the signing flow end-to-end while
that gets ironed out.
Complete Command Reference — Requirement Traceability
The seven stages above are the core happy-path flow. A real implementation needs the full command set below — every row maps to the specific requirement(s) it exists to satisfy, across all four sections of the spec. "—" means that category genuinely doesn't apply to that row, rather than forcing a stretch connection.
Scope of Work (SW) — SW1: complete hardware–software integration stack (token driver, security layer, middleware, SDK, API). SW2: native SDKs + JS bridge, framework-agnostic. SW3: vendor-agnostic support, no single-manufacturer dependency. SW4: reference/demo apps incl. WebView. SW5: complete digital signature workflow (detection, cert enumeration, PIN, signing, embedding/verification).
Functional Requirements (FR) — FR1: detect/communicate with dongle. FR2: enumerate certs, PIN auth, key never leaves dongle. FR3: sign PDF/XML/text. FR4: simple API/SDK, any dev stack. FR5: verifiable signatures, timestamping, clear error handling.
Security & Compliance (Sec) — Sec1: CCA/IT Act 2000 conformance, X.509 certs from Indian CCA-licensed CAs. Sec2: crypto executed on-token, PIN/key never cached/logged/transmitted. Sec3: protection against replay/MITM/tampering, integrity verifiable by standard validators. Sec4: security architecture document (threat model, data flows, compliance mapping).
Deliverables (Del) — Del1: working solution (SDKs, WebView bridge, middleware, token driver layer, source code). Del2: demo apps + live demonstration. Del3: documentation (technical architecture, security architecture, integration guide, API reference, CCA compliance). Del4: concept note, presentation, screenshots, demo video.
| # | Command / Function | Layer | What It Does | Scope of Work | Functional Req. | Security & Compliance | Deliverable |
|---|---|---|---|---|---|---|---|
| Session / Device Management | |||||||
| 1 | SELECT / GET_DEVICE_INFO | Device APDU | Identifies the dongle and its capabilities (the spec's "CTRL" identity step). | SW5 | FR1 | — | Del1 |
| 2 | RESET | Device APDU | Power-cycles the session without a full USB replug. | SW1 | FR1, FR5 | — | Del1 |
| Authentication | |||||||
| 3 | VERIFY_PIN | Device APDU | The spec's "PIN (authentication)" step — checked on-device, never leaves it. | SW5 | FR2 | Sec2 | Del1 |
| 4 | CHANGE_PIN | Device APDU | User-initiated PIN change, same on-device guarantee as verify. | SW1 | FR2 | Sec2 | Del1 |
| 5 | UNBLOCK_PIN (PUK recovery) | Device APDU | Resets a locked-out PIN using a recovery code, without extracting key material. | SW1 | FR5 — "wrong PIN" named explicitly | Sec2 | Del1 |
| 6 | GET_PIN_RETRIES | Device APDU | Reports remaining PIN attempts before lockout. | — | FR5 | — | Del1 |
| Key Management | |||||||
| 7 | GENERATE_KEY_PAIR | Device APDU | The spec's "PUF (root key) → ECDSA (key pair)" step — key pair generated on-device from the hardware root key. | SW1 | FR2 — private key must never leave the dongle | Sec2 — crypto executed on-token | Del1 |
| 8 | GET_PUBLIC_KEY | Device APDU | Exports only the public key — the spec's explicit "Only the public key leaves the device." | SW5 | FR2 | Sec2 | Del1 |
| 9 | DELETE_KEY | Device APDU | Key lifecycle/re-issuance support (lost device, re-enrollment). | SW1 | — | Sec4 — feeds the security architecture document | Del3 |
| Certificate Management | |||||||
| 10 | IMPORT_CERTIFICATE | Device APDU | Loads the CA-signed X.509 certificate back onto the device after CA enrollment. | SW5 | FR2 | Sec1 — X.509 certs from Indian CCA-licensed CAs | Del1 |
| 11 | GET_CERTIFICATE | Device APDU | Reads a stored certificate. | SW5 | FR2 — enumerate certificates | — | Del1 |
| 12 | GET_CERTIFICATE_CHAIN | Device APDU | Returns the full chain (intermediate + root CA) needed for independent verification. | SW5 | FR5 — verifiable signatures | Sec3 — integrity verifiable by standard validators | Del1 |
| 13 | LIST_CERTIFICATES | Device APDU | Enumerates multiple stored identities if the token supports more than one. | SW5 | FR2 — allow user selection | — | Del1 |
| Signing Operations | |||||||
| 14 | SIGN_HASH (PSO: Compute Digital Signature) | Device APDU | The core operation — signs a hash with the on-device private key; the key itself never crosses back out. | SW5 | FR3, FR2 | Sec2 — private key stays on-token | Del1 |
| 15 | GET_SIGNING_ALGORITHM_INFO | Device APDU | Reports supported algorithms/curves for interoperability. | — | FR5 — standards-compliant | — | Del1 |
| Timestamping | |||||||
| 16 | REQUEST_TIMESTAMP | Host-side (TSA call) | Obtains an RFC 3161 timestamp from a Time Stamping Authority, embedded alongside the signature. | — | FR5 — "timestamping support," named explicitly | — | Del1 |
| Device Lifecycle & Security | |||||||
| 17 | LOCK_DEVICE / FACTORY_RESET | Device APDU | Administrative wipe/lock, e.g. for a lost or compromised dongle. | SW1 | — | Sec3 — protection against tampering | Del1 |
| 18 | GET_SECURITY_STATUS / tamper status | Device APDU | Reports tamper flags if the hardware supports detection. | SW1 | — | Sec3 — protection against tampering | Del3 |
| 19 | FIRMWARE_VERSION / secure-boot attestation | Device APDU | Reports firmware/attestation info for audit purposes. | SW1 | — | Sec4 — feeds the security architecture document | Del3 |
| Cross-Cutting | |||||||
| 20 | Consistent SW1SW2 status-word taxonomy | Device APDU (all commands) | Every command above returns through the same error-code system (no dongle, wrong PIN, expired certificate, etc.) — this is scope across all ~19 device commands, not a separate feature. | SW5 | FR5 — clear error handling, named with these exact examples | — | Del3 |
| Host / SDK Layer (not device commands) | |||||||
| 21 | SDK wrapper functions (detectDongle(), enumerateCertificates(), authenticate(), sign(), ...) | SDK | The simple, documented API app developers actually call — wraps every device command above. | SW1, SW2 | FR4 — minimal integration code | — | Del1, Del3 — this is what the API reference documents |
| 22 | WebView JavaScript bridge | SDK / JS | Exposes the same SDK surface to WebView pages via addJavascriptInterface (Android) / WKScriptMessageHandler (iOS). | SW2 — "JavaScript bridge/interface... WebView applications" | FR4 — framework-agnostic | — | Del1, Del2 — exercised by the WebView demo |
| 23 | PAdES / XMLDSig / raw-hash container building | SDK | Wraps the raw signature from SIGN_HASH into a standards-compliant PDF, XML, or hash signature container. | SW5 | FR3 | — | Del1 |
| 24 | Vendor-agnostic PKCS#15 generic client | Middleware | Reads any compliant token's standard object layout instead of a vendor-specific one. | SW3 — "no dependency on a single token manufacturer" | — | — | Del1 |
| 25 | Independent signature verification | Host-side (SDK or recipient's own tools) | Confirms a signature against the public certificate — no device involved. | SW5 — "signature embedding/verification" | FR5 | Sec3 — verifiable by standard validators | — |
SecureSign — Status & Roadmap
Current state of the STM32F417 prototype scored against the ten-category, 100-mark evaluation rubric,
what's still missing in each category, and the next steps to close the gaps. Reflects only what has been verified this
session (live opensc-tool / PC-SC testing over the working CDC+CCID USB link) — not aspirational claims.
| Category | Marks | Status | Evidence / Current State | Gap / What's Needed |
|---|---|---|---|---|
| Technical Feasibility | 12 | Proven | Full end-to-end flow works on real hardware: USB composite CDC+CCID enumerates, ATR completes, SELECT → VERIFY PIN → PSO: COMPUTE DIGITAL SIGNATURE all succeed against opensc-tool/PC-SC, returning a valid 64-byte P-256 signature (SW=9000) in under 700 ms. Certificate SELECT + READ BINARY (611 bytes) also verified, including USB packet chunking and CCID GET RESPONSE (61xx) handling. |
— |
| Performance & Reliability | 10 | Working | Full PIN-verify-and-sign round trip completes in well under a second. Boot is stable after fixing the bootloader stack-pointer validation, watchdog timing, and CCID multi-packet transfer bugs found this session — no resets observed across repeated testing. | Signing currently executes synchronously inside the USB interrupt path. Fine at P-256 speeds on this prototype, but should move to a task context before scaling to slower operations. |
| Innovation & Originality | 10 | Partial | Digital Signature Certificates remain bound to the desktop: every hardware token ships with its own vendor driver, and that dependency is precisely why DSC signing has never reached mobile. SecureSign removes it. One driverless, generic Type-C dongle integrates with any Android, iOS, or Windows application — native or WebView, regardless of stack — delivering the same plug-and-play signing experience users expect on desktop, fully compliant with CCA guidelines. Its onboarding sequence is rooted in hardware at every step: CTRL establishes device identity, PIN authenticates the user, the FPGA's PUF derives a unique hardware root key, and the ECDSA key pair is generated on-device directly from that root — the private key never leaves the silicon; only the public key does. This prototype validates that protocol on real USB hardware, end to end: driverless CCID enumeration, on-device PIN verification, and on-device signing, with an MCU and mbedTLS software cryptography standing in for the FPGA's dedicated crypto engines. | The mobile-facing half of the innovation — Android/iOS SDK, WebView bridge, and the FPGA target itself (USB device controller, CCID/APDU parser, command dispatcher, SPI/I²C/GPIO masters, AES/SHA/ECC/RSA engines, TRNG, Key Manager, flash controller) — is not yet built. This board is a desktop-only proof of the protocol, not the cross-platform dongle itself. |
| Security Architecture | 15 | Partial | On-device PIN gate and deterministic ECDSA (RFC 6979, mbedTLS) signing implemented and tested — the private key never leaves the device during signing. | Demo private key is embedded in flash rather than generated/held in a secure element (this MCU has none). No written security-architecture document yet (threat model, data flows, key custody). |
| Compliance with CCA Guidelines | 15 | Partial | PKCS#15 file structure (EF(DIR)/ODF/AODF/PrKDF/CDF/TokenInfo) implemented on-card and fully readable by
standard tooling — pkcs15-tool --dump correctly lists the PIN, the private EC key (with correct
usage/path/algorithm reference), the X.509 certificate, and declared algorithm support (CKM_ECDSA), after
fixing eight firmware bugs this session. The private key is also fully visible via PKCS#11
(pkcs11-tool --list-objects), with matching CKA_ID against the certificate. PKCS#11 signing
now works end-to-end through three independent real-world clients: pkcs11-tool --sign, a
PyKCS11 Python application, and jSignPdf actually signing a PDF (CMS signature independently verified).
That required two genuine OpenSC-side fixes (the generic driver never registered a signing mechanism at
all — patched card-default.c; and pkcs15_prkey_can_do() blocked the combined
SHA-256 mechanism Java-based callers request directly) plus one firmware fix (PrKDF
fieldSize). See the Testing Guide tab, TC 2.4/2.5/3.2/3.3. |
Certificate is self-signed, not issued by a CCA-licensed CA. No GENERATE_KEY_PAIR, CHANGE_PIN, UNBLOCK_PIN, or GET_PIN_RETRIES — key/PIN are fixed demo values, not provisioned per requirements. |
| Interoperability Across Platforms | 10 | Partial | Confirmed working on Windows via PC/SC and OpenSC, using the standard driverless CCID class. | Not yet tested on Linux/macOS PC/SC. No mobile (Android/iOS) path exists yet. |
| User Experience | 8 | Minimal | On-device LCD shows live status (PIN / cert / sign / last event) driven off a lock-free event queue fed from the USB ISR. | No host-side application yet — testing today is command-line only via opensc-tool. |
| Ease of Integration | 8 | Not started | — | No SDK or wrapper layer yet — every test so far talks raw APDUs directly. Need a thin host SDK (detect / verify PIN / sign / read cert) so integrators don't need PC/SC or APDU knowledge. |
| Scalability & Maintainability | 6 | Prototype-only | Single hardcoded demo key and PIN, by design, for this proof-of-concept. | Production is intended to move to different target hardware (STM32U585 + FPGA) rather than extend this prototype's key handling. |
| Deployment Readiness | 6 | Not started | — | No packaged submission deliverables yet — demo app, documentation set, concept note, or walkthrough video. |
Next Panel — Roadmap
Ordered by what unblocks the most rubric categories per step of effort — command-set gaps first, since they're referenced by both Security Architecture and CCA Compliance, then integration, then platform breadth, then packaging.
| # | Next Step | Why It Matters | Closes Gap In |
|---|---|---|---|
| 1 | Verify PKCS#15 at the tooling level | Run pkcs15-tool / pkcs11-tool against the device, not just raw APDUs, to catch anything a real signing client would trip on that opensc-tool --send-apdu testing can't reveal. | Technical Feasibility, Interoperability |
| 2 | Implement the missing card commands | CHANGE_PIN, UNBLOCK_PIN, GET_PIN_RETRIES, GET_CERTIFICATE_CHAIN, and a timestamp request — the set most compliance and security gaps trace back to. | Security Architecture, CCA Compliance |
| 3 | Write the security architecture document | Key custody, PIN handling, threat model, and what's demo-only vs. production-real. Directly required, not just implied. | Security Architecture, CCA Compliance, Deployment Readiness |
| 4 | Build a minimal host SDK + demo app | Wraps detect/verify/sign/read-cert so the device can be integrated without APDU knowledge. | Ease of Integration, User Experience |
| 5 | Test on Linux/macOS, then scope mobile | Confirm PC/SC behavior beyond Windows before committing to an Android/iOS SDK effort. | Interoperability |
| 6 | Plan the production hardware move | Define what changes — secure key storage, CA-issued certificate, real GENERATE_KEY_PAIR on a secure element — when moving off this prototype MCU to STM32U585 + FPGA. | Scalability & Maintainability, CCA Compliance |
| 7 | Assemble submission deliverables | Demo app, documentation, concept note, and a recorded walkthrough of the working SELECT → VERIFY → SIGN flow. | Deployment Readiness |
opensc-tool and serial-log testing. This is not a production security claim — see the
Flow Reference tab for how each stage compares against the intended production target
(STM32U585 + FPGA) and today's hardware-token / software-DSC alternatives.
SecureSign — Testing Guide
Test cases for the STM32F417 prototype dongle, organized in four levels — device/APDU, PKCS#15/PKCS#11, real application, and reliability. Run each level in order: a failure at Level 1 explains a failure at every level above it.
| TC# | Objective | Command | Expected Result | Status |
|---|---|---|---|---|
| 1.1 | Device enumerates as composite CDC + CCID | Windows Device Manager → Ports (COM) & LPT + Smart card readers | One CDC COM port and one "SEQUENTIA SecureSign Dongle" reader appear, no driver install prompt | Verified |
| 1.2 | Reader is visible to PC/SC | opensc-tool --list-readers | Reader listed by name, card present | Verified |
| 1.3 | ATR retrieval | opensc-tool --atr | 19-byte T=0 ATR returned, no SCARD_STATE_MUTE | Verified |
| 1.4 | SELECT by AID/FID | opensc-tool --send-apdu 00A4000C023F00 | SW=9000 | Verified |
| 1.5 | READ BINARY on certificate EF, with chaining | opensc-tool --send-apdu 00B0000000 (611-byte cert, exceeds one 64-byte CCID packet) | Full DER certificate returned intact via GET RESPONSE (61xx) chaining; matches embedded demo cert byte-for-byte | Verified |
| 1.6 | VERIFY PIN — correct value | opensc-tool --send-apdu 002000010431323334 | SW=9000 | Verified |
| 1.7 | VERIFY PIN — wrong value, retry counter | Send VERIFY with an incorrect PIN once | SW=63C2 (2 tries remaining), no crash, correct PIN still works after | Verified — SW=63C2, correct PIN worked afterward (retries reset to 3) |
| 1.8 | PIN lockout after repeated failures | Send VERIFY with wrong PIN three times in a row | SW=6983 on the 3rd attempt and on all further attempts, including with the correct PIN | Verified — 63C2 → 63C1 → 6983, then 6983 even with the correct PIN |
| 1.9 | PSO: COMPUTE DIGITAL SIGNATURE | opensc-tool --send-apdu 002A9E9A20<32-byte-hash> | 64-byte raw r‖s ECDSA signature, SW=9000, completes in <700 ms | Verified |
| 1.10 | Signature validity (independent check) | openssl dgst -verify pub.pem -signature test.sig test.hash against the r‖s from TC 1.9 (DER-wrapped) | OpenSSL reports Verified OK | Verified — openssl dgst -sha256 -verify pub.pem -signature sig.der msg.txt reports Verified OK |
| 1.11 | Signing without prior PIN verify is rejected | Power-cycle card, send PSO:SIGN without VERIFY first | SW=6982 (security status not satisfied) | Verified — SW=6982 on PSO:SIGN attempted immediately after a fresh power-on, before any VERIFY |
| 1.12 | Malformed APDU handling | Send a truncated/incomplete APDU | Clean error status word (e.g. SW=6A86), no hang, device remains responsive to the next command | Verified — a raw APDU with an unsupported INS byte (00 FF 00 00) returns SW=6D00; SELECT sent immediately after still returns SW=9000 normally. A genuinely truncated (<4-byte) APDU can't reach the device at all — both opensc-tool and Windows' own T=0 SCardTransmit reject it locally first. |
0x81,
but the firmware's actual SS_PIN_REFERENCE is 0x01 — P2=0x81 is correctly
rejected with SW=6A88; P2=0x01 is what actually works. The commands above now reflect
the correct value.
| TC# | Objective | Command | Expected Result | Status |
|---|---|---|---|---|
| 2.1 | Generic PKCS#15 driver parses the on-card file system | pkcs15-tool --dump | ODF, AODF, PrKDF, CDF, and TokenInfo all parse without errors | Verified — all five files parse cleanly, including the private key entry (see note below for the full fix chain). pkcs15-tool --dump shows the PIN, "Private EC Key [SecureSignKey]" with correct usage/path/algo_refs, the certificate, and declared CKM_ECDSA support |
| 2.2 | Certificate enumeration via OpenSC | pkcs15-tool --list-certificates | Demo certificate listed with correct label/usage | Verified — "SecureSignCert" listed with correct path/ID/serial |
| 2.3 | PKCS#11 object listing | pkcs11-tool --module opensc-pkcs11.dll --list-objects | Private key and certificate objects both listed, correct CKA_ID linkage | Verified — Private Key Object (EC, usage=sign), Certificate Object, and its derived Public Key Object all list correctly with matching CKA_ID (0x45/"69") and correct prime256v1 params |
| 2.4 | PKCS#11 login | pkcs11-tool --module opensc-pkcs11.dll --login --pin 1234 --test | Login succeeds, built-in self-test signs and verifies successfully | Verified — login succeeds and the self-test's signing step now completes (see TC 2.5 note: required an OpenSC source patch) |
| 2.5 | PKCS#11 sign via mechanism | pkcs11-tool --sign --mechanism ECDSA --login --pin 1234 -i data.bin -o data.sig | Signature file produced, verifies against the public certificate | Verified — a real ECDSA signature is produced and independently verifies with OpenSSL (openssl pkeyutl -verify -pubin → "Signature Verified Successfully"). Root cause was genuinely OpenSC-side (see note below): fixed by patching card-default.c to register the ECDSA capability, plus one more firmware fix (PrKDF fieldSize) surfaced once the OpenSC side no longer masked it |
pkcs11-tool --sign produces a signature that independently verifies with OpenSSL.
| TC# | Objective | Method | Expected Result | Status |
|---|---|---|---|---|
| 3.1 | A real PDF-signing application recognizes the token | jSignPdf (free, open-source; Adobe Acrobat Pro is a paid product) configured with a PKCS#11 keystore pointing at opensc-pkcs11.dll | Demo identity appears as a usable signing key | Verified — jSignPdf's key listing returns SecureSignCert as a usable key alias |
| 3.2 | End-to-end PDF signing | Sign a PDF with jSignPdf using the SecureSignCert identity | PAdES/CMS signature embedded; signature cryptographically verifies | Verified — a real PDF is signed and the embedded CMS signature independently verifies (ECDSA/SHA-256 over the signed attributes). Required an OpenSC-side fix (pkcs15_prkey_can_do()) since jSignPdf/Java request the combined CKM_ECDSA_SHA256 mechanism directly |
| 3.3 | Programmatic sign/verify via PyKCS11 | Small Python script: load module, login(pin), sign(hash), verify against public cert | Script reports signature valid, matching TC 1.9/1.10 result through a real application-layer API | Verified — full script run against the real installed module. Load, login, and sign() with CKM_ECDSA all succeed, returning a signature that independently verifies with OpenSSL. |
| 3.4 | OpenSSL engine signing (libp11) | openssl dgst -engine pkcs11 -keyform engine -sign "pkcs11:object=...", -out out.sig file.txt | Signature produced without any vendor-specific code, using only standard OpenSSL + PKCS#11 engine | Partial — libp11's engine was built from source and correctly registers with OpenSSL, but its own module-load step hits a native-process DLL-loading quirk specific to this machine (the same file loads fine via Java/Python). Not a signing-capability gap — already proven by TC 2.5/3.2/3.3 |
securesign_webapp/ (Flask) wraps the same
jSignPdf signing path behind an actual web UI — upload a PDF, enter the PIN, download the signed result —
closer to how a real DSC-signing portal is structured (local backend with token access, browser UI on top)
than driving jSignPdf from the command line. PIN is passed to the signing process over stdin, never as a
command-line argument or in any log. Confirmed working end-to-end, including the wrong-PIN error path and
PIN-retry recovery.
| TC# | Objective | Method | Expected Result | Status |
|---|---|---|---|---|
| 4.1 | No unexpected resets under normal use | Run TC 1.4 → 1.9 in a loop 20+ times, watch CDC log | No IWDG reset, no hang, consistent timing each pass | Verified (stable across repeated testing this session) |
| 4.2 | Power-on without debugger attached | Unplug/replug the dongle directly (no ST-Link session) | Enumerates and responds identically to the debugger-attached case | Verified (root cause of the earlier boot-hang was fixed) |
| 4.3 | LCD status reflects live flow state | Watch LCD while running SELECT → VERIFY → SIGN from a host | Status rows update per stage (Idle → Card ON → PIN OK → Sign OK) without flicker or garbled text | Verified |
| 4.4 | CDC debug log is readable and correctly tagged | Open the CDC COM port in a serial terminal during a test run | Each line is [MODULE] Message. format, no garbled/binary output | Verified |
opensc-tool.exe confirmed
working this session) and, for Level 3, jSignPdf (free) or a small PyKCS11 script pointed at
opensc-pkcs11.dll (typically under C:\Program Files\OpenSC Project\OpenSC\pkcs11\).
Adobe Acrobat Pro also works but is a paid product. See the Flow Reference tab for how each stage maps to the
production (STM32U585 + FPGA) target. Setting up a different PC from scratch (install steps,
packages, patched OpenSC download)? See the
standalone setup guide.
Testing Setup — From a Blank PC
Everything needed to set up a fresh Windows PC to test the SecureSign dongle, from a blank machine to running the Level 1–3 test cases in the Testing Guide tab. No firmware rebuild required — this is for testing an already-flashed device.
Setup-SecureSign.ps1 automates Steps 1–7 below —
installs OpenSC if missing, deploys the patched module, optionally registers the friendly device name,
installs jSignPdf, checks Python/Flask, and downloads the web app. Safe to re-run (skips anything already
done). Download it directly:Setup-SecureSign.ps1
... or fetch and run it in one go, in an elevated PowerShell:
iwr https://securesigndongle.rioncore.com/downloads/Setup-SecureSign.ps1 -OutFile Setup-SecureSign.ps1
.\Setup-SecureSign.ps1
It self-elevates (UAC prompt) if not already running as Administrator. See
Get-Help .\Setup-SecureSign.ps1 -Full for parameters (custom install path, skipping individual
steps). Prefer doing it by hand, or want to understand each step first? Continue reading below.
Bookmark or share this page to come back to this guide: securesigndongle.rioncore.com/#setup
1. Hardware & OS requirements
| Item | Requirement |
|---|---|
| PC | Windows 10 or 11, 64-bit |
| Device | SecureSign USB CCID dongle (STM32F417 prototype), already flashed with firmware |
| Cable | USB cable matching the board's connector (no drivers needed — driverless composite CDC + CCID device) |
| Admin rights | Required for installing OpenSC and replacing files under C:\Program Files\ |
2. Install and patch OpenSC (required for all levels)
- Download and install the official OpenSC Windows build (0.27.x, 64-bit MSI) from
github.com/OpenSC/OpenSC/releases. Accept all defaults — it installs to
C:\Program Files\OpenSC Project\OpenSC\. - Plug in the SecureSign dongle. Windows should enumerate it with no driver prompt — check Device Manager for a COM port and a reader under "Smart card readers" (may show as "Unknown Smart Card" until Step 3 below — cosmetic only).
- Download the patched OpenSC module package:
opensc_patch_package.zip (~7 MB)
Contains two folders,tools\andpkcs11\, mirroring the install layout. - Close any running OpenSC processes (Task Manager → end
opensc-notify.exeif present, it can lock the DLL). - Copy the files over the installed ones, in an elevated PowerShell/cmd:
This replacescopy /Y "<extracted>\tools\*" "C:\Program Files\OpenSC Project\OpenSC\tools\" copy /Y "<extracted>\pkcs11\*" "C:\Program Files\OpenSC Project\OpenSC\pkcs11\"opensc.dll,opensc-pkcs11.dll, and theirlibcrypto-3-x64.dll/zlib1.dllruntime dependencies with the patched build. It does not touchonepin-opensc-pkcs11.dllor any other card-specific tool. - Verify the patch took effect:
Should list the SecureSign reader and return a 19-byte ATR with no error.cd "C:\Program Files\OpenSC Project\OpenSC\tools" .\opensc-tool.exe --list-readers .\opensc-tool.exe --atr
1234 for every test below — a fixed demo value baked
into this prototype's firmware, not something you set up.
3. (Optional) Friendly device name in Windows
Without this, Device Manager may show "Unknown Smart Card" instead of "SEQUENTIA SecureSign Dongle". Purely cosmetic — every test works either way.
- Get the device's ATR:
opensc-tool --atr(from Step 2 above). - In an elevated PowerShell, create the registry key (use your device's actual ATR bytes):
Unplug and replug the device afterward.New-Item -Path "HKLM:\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\SEQUENTIA SecureSign Dongle" -Force Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\SEQUENTIA SecureSign Dongle" ` -Name "ATR" -Value ([byte[]](0x3B,0x9F,0x11, ...rest of your ATR bytes...)) Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Cryptography\Calais\SmartCards\SEQUENTIA SecureSign Dongle" ` -Name "ATRMask" -Value ([byte[]](0xFF,0xFF,0xFF, ...same length, all 0xFF...))
4. Level 1 — Device / Raw APDU testing
No extra install needed beyond Step 2. From
C:\Program Files\OpenSC Project\OpenSC\tools\:
.\opensc-tool.exe --list-readers
.\opensc-tool.exe --atr
.\opensc-tool.exe --send-apdu 00A4000C023F00
.\opensc-tool.exe --send-apdu 002000010431323334 REM VERIFY PIN 1234
Full command list and expected results: Testing Guide tab, Level 1 table (TC 1.1–1.12).
5. Level 2 — PKCS#15 / PKCS#11 tooling
Same directory, no extra install:
.\pkcs15-tool.exe --dump
.\pkcs15-tool.exe --list-certificates
.\pkcs11-tool.exe --module "C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll" --list-objects
.\pkcs11-tool.exe --module "C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll" --login --pin 1234 --test
.\pkcs11-tool.exe --module "C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll" ^
--sign --mechanism ECDSA --login --pin 1234 -i data.bin -o data.sig
Full command list and expected results: Testing Guide tab, Level 2 table (TC 2.1–2.5).
6. Level 3 — Real application testing
6a. PDF signing via jSignPdf (free, no license needed)
- Download
jsignpdf-3.1.0-windows-x64.zipfrom SourceForge (~130 MB — bundles its own Java runtime, so no separate JDK/JRE install is required). Extract it, e.g. toC:\jsignpdf\. - Create
C:\jsignpdf\config\pkcs11.cfg:name=SecureSign library=C:/Program Files/OpenSC Project/OpenSC/pkcs11/opensc-pkcs11.dll slotListIndex=0 - List the available signing key (confirms the token is recognized):
Should print$env:JSIGNPDF_CONFIG_DIR = "C:\jsignpdf\config" & "C:\jsignpdf\JSignPdf\JSignPdfC.exe" -kst PKCS11 -ksp 1234 -lkSecureSignCertas an available key alias. - Sign a PDF:
Produces& "C:\jsignpdf\JSignPdf\JSignPdfC.exe" -kst PKCS11 -ksp 1234 -ka SecureSignCert ` -r "Test signature" -l "Test Bench" --overwrite -d "C:\jsignpdf" "C:\path\to\your.pdf"your_signed.pdfwith a real embedded PAdES/CMS signature from the device.
6b. Programmatic sign/verify via PyKCS11 (Python)
- Install Python 3.10+ from python.org (check "Add to PATH" during install).
pip install PyKCS11(prebuilt wheel, no compiler needed).- Run:
import PyKCS11 pkcs11 = PyKCS11.PyKCS11Lib() pkcs11.load(r"C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll") slots = pkcs11.getSlotList(tokenPresent=True) session = pkcs11.openSession(slots[0], PyKCS11.CKF_SERIAL_SESSION | PyKCS11.CKF_RW_SESSION) session.login("1234") priv = session.findObjects([(PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY)])[0] sig = session.sign(priv, b"\x00" * 32, PyKCS11.Mechanism(PyKCS11.CKM_ECDSA, None)) print("signature:", bytes(sig).hex()) session.logout() session.closeSession()
7. Troubleshooting
| Symptom | Cause / Fix |
|---|---|
Device shows in Device Manager but opensc-tool --list-readers lists nothing |
Windows Smart Card service isn't running: Start-Service SCardSvr (elevated PowerShell) |
CKR_MECHANISM_INVALID on pkcs11-tool --sign |
The patched DLLs weren't actually deployed — verify with
Get-FileHash "C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll". If wrong,
another process may be re-locking/reverting the file — close all OpenSC processes and retry the copy. |
Copy to Program Files fails with "file in use" |
Get-Process | Where-Object {$_.ProcessName -match "opensc|pkcs11|pkcs15|scardsvr"}, stop
any match, retry |
jSignPdf: PKCS11 KeyStore not available |
$env:JSIGNPDF_CONFIG_DIR isn't set, or pkcs11.cfg isn't in that exact
folder — the provider is registered automatically only from that specific location |
jSignPdf: CKR_SLOT_ID_INVALID |
Device not detected right now — check opensc-tool --list-readers works first; replug the
device if needed |
PyKCS11: LoadLibrary() failed with error 127 |
Add the pkcs11 directory to PATH before loading, in Python before
import PyKCS11: os.environ["PATH"] = r"C:\Program Files\OpenSC Project\OpenSC\pkcs11" + os.pathsep + os.environ["PATH"] |
card-default.c, framework-pkcs15.c), and Windows-specific build fixes are
documented in the
standalone setup guide's appendix.
8. Running the "Sign a PDF" tab (127.0.0.1:5001)
The Sign a PDF tab needs a small local service running on your own PC — the dongle can't be reached from a remote server, so this page is only the UI; the actual signing happens locally. To get it working, someone needs all of the following on their own PC:
- Windows 10/11 PC with admin rights.
- A physical SecureSign dongle, plugged into that PC via USB — this is the hard requirement; there's no way around needing the actual hardware.
- OpenSC installed + patched — the official installer, then overlay the patched DLLs (Step 2 above).
- jSignPdf installed — free download, self-contained (bundles its own Java runtime), just needs extracting + the small config file (Step 6a above).
- Python 3.10+ installed, then
pip install flask. - Download and extract the signing app:
securesign_webapp.zip - Run
python app.pyfrom that folder — this starts the local service on port 5001. - Then open either
http://127.0.0.1:5001directly, or this website's Sign a PDF tab — both work identically, since the hosted tab just calls back to127.0.0.1:5001on that same machine.
Without step 7 (app.py actually running) and step
2 (the real dongle plugged in), nothing on that tab will work — it'll just show "local signing service
not reachable."
Sign a PDF with SecureSign
A real, working PDF-signing demo, not just test tooling — upload a PDF, enter the device PIN, get back a genuinely signed document. Runs through a small local backend on your own PC, since the dongle can't be reached from a remote server; this page is just the UI.
http://127.0.0.1:5001 — start it
with python app.py from the securesign_webapp folder before using the form
below. See the
Setup Guide
tab if it's not installed yet.
Sign a PDF
The document is signed on your own machine using the private key inside the connected SecureSign dongle — the key itself never leaves the device, and the file never leaves your machine either (this only talks to the local service on 127.0.0.1, not to this website's server).
Run Level 1 / Level 2 Test Commands
The same commands from the Testing Guide's Level 1 (raw APDU) and Level 2 (PKCS#15/PKCS#11) tables, run for real against the connected device, with the actual output shown below each one. Commands marked PIN use the PIN entered above.
opensc-tool --list-readersopensc-tool --atropensc-tool --send-apdu 00A4000C023F00opensc-tool --send-apdu 00A4080C06501550154331 --send-apdu 00B0000000opensc-tool --send-apdu 0020000104<pin-hex>pkcs15-tool --dumppkcs15-tool --list-certificatespkcs11-tool --module opensc-pkcs11.dll --list-objectspkcs11-tool --login --pin <pin> --testpkcs11-tool --sign --mechanism ECDSA --login --pin <pin> -i data.bin -o data.sigRequirement Specification — SecureSign Type-C DSC Dongle Mobile Signing Solution
Sequentia's original requirement document in full, reformatted for the site. This is the source of truth the Flow Reference, Status & Roadmap, and Testing Guide tabs are all built against.
1. Background & Objective
The SecureSign requirement is to solve a real-world gap: Digital Signature Certificate (DSC) signing today works only on desktops. The objective is the end-to-end development of a generic Type-C DSC dongle signing solution that integrates seamlessly with mobile apps and mobile WebView applications — irrespective of the app's development stack — on both Android and iOS, giving users a plug-and-play signing experience comparable to desktop DSC signing, fully conforming to CCA (Controller of Certifying Authorities) guidelines.
Onboarding / login flow: the host confirms the device identity, authenticates the user with a PIN, then has the device derive its hardware root key and generate the DSC key pair. Only the public key leaves the device.
CTRL (identity) → PIN (authentication) → PUF
(root key) → ECDSA (key pair). Responses: pin_ok, key_ready, and the
public key.
2. Scope of Work (Full Solution Build)
- Design and develop the complete hardware–software integration stack: token driver integration, security layer, middleware, SDK, and API framework for Type-C DSC dongles.
- Native SDKs for Android and iOS, plus a JavaScript bridge/interface enabling signing from mobile WebView applications, framework-agnostic (native, Flutter, React Native, hybrid web).
- Vendor-agnostic support for commonly used CCA-approved Type-C DSC tokens (e.g., PKCS#11-compliant tokens); no dependency on a single token manufacturer.
- Reference/demo mobile applications on Android and iOS demonstrating the full signing workflow, including a WebView demonstration.
- Complete digital signature workflow: dongle detection, certificate enumeration and selection, PIN authentication, document signing (PDF, XML, text), and signature embedding/verification.
3. Functional Requirements
- FR1: Detect and communicate with a Type-C DSC dongle on plug-in (USB-C OTG on Android; supported connectivity per Apple MFi/USB-C on iOS).
- FR2: Enumerate certificates on the token, allow user selection, and authenticate via token PIN; private key must never leave the dongle.
- FR3: Sign PDF (PAdES-compatible), XML (XMLDSig), and text/hash payloads invoked from a host mobile app or WebView page.
- FR4: Expose a simple, documented API/SDK so any third-party app can integrate signing with minimal code, independent of its development stack.
- FR5: Return verifiable, standards-compliant signatures with timestamping support and clear error handling (no dongle, wrong PIN, expired certificate, etc.).
4. Security & Compliance Requirements
- Full conformance to CCA guidelines and IT Act, 2000 provisions for digital signatures; support X.509 certificates issued by Indian CCA-licensed CAs.
- Cryptographic operations executed on-token; PIN and key material never cached, logged, or transmitted. Secure channel between app, middleware, and token.
- Protection against replay, man-in-the-middle, and tampering; signed-data integrity verifiable by standard validators.
- Security architecture document covering threat model, data flows, and compliance mapping (to be part of deliverables).
5. Deliverables
- Working solution: Android SDK, iOS SDK, WebView bridge, middleware, and token driver integration layer — with source code (repository access to Sequentia).
- Demo apps (Android & iOS) and live demonstration of the end-to-end signing workflow, including WebView flow.
- Documentation: technical architecture document, security architecture overview, integration guide, API reference, and CCA compliance documentation.
- Concept note, solution presentation, prototype screenshots, and demo video in formats required by the challenge portal (file-size limits apply).
6. System Architecture — Communication Stack
Every signing call travels down one fixed stack, from the application on the host to the secure element on the dongle. Nothing above the STM32 / FPGA line ever sees the private key — it terminates inside the secure element and only status words and signatures travel back up.
On this prototype: the STM32F417 stands in for the STM32/FPGA layer, and mbedTLS software crypto stands in for the secure element — the stack above it (PKCS#11 → PC/SC → USB CCID) is real and unchanged from the production target.
7. How Digital Signing Actually Works (explainer, not part of the original requirement text)
The most common question about this whole system: "once a document is signed, does someone need the dongle plugged in to open or check it later?" No — and understanding why is the key to understanding the whole design.
Think of it like a padlock with two different keys, not one key that both locks and unlocks:
- Key A (the private key) — can only be used to lock the padlock. This key lives inside the SecureSign dongle's secure element and physically never comes out of it, ever.
- Key B (the public key) — can only be used to check that the padlock was locked correctly, and by which padlock. This key is not a secret — copies of it are handed out to everyone, and one travels inside every document the dongle signs, as part of the signer's X.509 certificate.
Signing a document (needs the dongle):
- The host sends the document's data to the dongle.
- Inside the dongle, Key A locks a cryptographic seal onto that data — Key A never leaves the secure element to do this.
- That seal, plus a copy of Key B (the certificate), gets embedded into the document before it's saved. The signed file now physically contains: the document + the seal + a copy of Key B.
Opening/verifying it later (does not need the dongle):
- The reader (e.g. Adobe Acrobat) finds the seal and the copy of Key B already embedded in the file — it doesn't ask the original signer or their dongle for anything.
- It uses that Key B to check: does this seal match this exact document, and was it produced by the Key A that pairs with this Key B? This is pure math, done in software — no hardware required, because Key B was never secret.
Why it can't be faked: only Key A can produce a seal that Key B accepts. Since Key A never leaves the dongle, nobody else can produce a valid seal — but anyone, anywhere, on any computer, can run the check, forever, using the Key B copy already sitting inside the file. That's the whole trick of public-key cryptography: the checking half is meant to be public and travels with the document; only the locking half needs to stay secret, which is exactly what the dongle's secure element is for.
Separate point — "trusted" vs. "unknown" signatures: whether a reader shows a green trusted checkmark or a yellow "unknown" icon depends on whether that reader already trusts who issued the certificate — e.g. this prototype's demo certificate is self-signed, not issued by a CCA-licensed CA, so readers will correctly show it as unverified/untrusted even though the underlying cryptographic signature is fully valid. That trust decision happens entirely on the verifier's side and has nothing to do with needing the signing device.