Skip to content

fix: re-create PCSCCardConnection to avoid stale hcontext on pyscard >= 2.2 - #1

Open
calu777 wants to merge 1 commit into
edeustua:mainfrom
calu777:fix/pyscard-2.2-compat
Open

fix: re-create PCSCCardConnection to avoid stale hcontext on pyscard >= 2.2#1
calu777 wants to merge 1 commit into
edeustua:mainfrom
calu777:fix/pyscard-2.2-compat

Conversation

@calu777

@calu777 calu777 commented May 9, 2026

Copy link
Copy Markdown

Summary

Fixes a TypeError: Expected a python long as SCARDCONTEXT raised when calling any peru-dnie command (extract, sign) on systems shipping pyscard 2.2 or newer, such as Debian 13 with Python 3.13.

Symptom

$ peru_dnie extract signature /tmp/test.crt
[...]
  File ".../smartcard/pcsc/PCSCCardConnection.py", line 131, in connect
    hresult, self.hcard, dwActiveProtocol = SCardConnect(
        self.hcontext, str(self.reader), mode, pcscprotocol
    )
  File ".../smartcard/scard/scard.py", line 600, in SCardConnect
    return _scard.SCardConnect(hcontext, readername, dwShareMode, dwPreferredProtocols)
TypeError: Expected a python long as SCARDCONTEXT.

Root cause

Under pyscard 2.2.x, CardRequest.waitforcard() (via PCSCCardRequest) establishes its own SCARD context, uses it to wait for and identify the card, and releases that context before returning. The card_service it returns carries a connection whose hcontext is now None.

When peru-dnie subsequently calls connection.connect(), PCSCCardConnection.connect() tries to call SCardConnect(self.hcontext, ...) with hcontext = None, which fails the type check in pyscard's C extension.

This was confirmed by inspecting the connection returned by get_dnie_connection():

type(conn.component): <class 'smartcard.pcsc.PCSCCardConnection.PCSCCardConnection'>
type(conn.component.hcontext): <class 'NoneType'>
repr(conn.component.hcontext): None

Fix

Instead of returning card_service.connection directly -whose context has been released- construct a fresh PCSCCardConnection from the reader that waitforcard() already identified. The PCSCCardConnection.__init__ calls SCardEstablishContext() and provides a valid hcontext.

return PCSCCardConnection(card_service.connection.component.reader)

The PCSCCardConnection(reader) constructor signature has been stable across pyscard 2.0.x and 2.2.x, so this is backward-compatible.

Testing

Verified on:

  • OS: Debian 13.4 (Trixie)
  • Python: 3.13
  • pyscard: 2.2.2 (system package python3-pyscard)
  • Hardware: Generic USB2.0-CRW reader, DNIe v2 (chip NXP JCOP3 SecID P60, applet RENIEC)

Operations tested:

# extract: succeeds, certificate matches FirmadorCliente output
$ peru_dnie extract signature /tmp/test.crt
DNIe V2 encontrado
Certificado cargado con éxito
Certificado escrito en 'test.crt'

$ openssl x509 -in /tmp/test.crt -noout -subject
subject=C=PE, ST=..., CN=... FIR ... hard

# sign: succeeds, signature verifies cryptographically
$ peru_dnie sign /tmp/test_sign.txt /tmp/test_sign.txt.sig
DNIe V2 encontrado
Por favor, introduce tu PIN: ****
[archivo firmado]

$ openssl x509 -pubkey -noout -in /tmp/test.crt > /tmp/test_pubkey.pem
$ openssl dgst -sha256 -verify /tmp/test_pubkey.pem \
    -signature /tmp/test_sign.txt.sig /tmp/test_sign.txt
Verified OK

Notes

  • No changes to public API; existing callers continue to work.
  • The fix does not require pinning a specific pyscard version — it works with both 2.0.x (current requirements.txt constraint) and 2.2.x.
  • Recommendation for a follow-up: relax pyscard~=2.0.7 in requirements.txt to pyscard>=2.0.7,<3 so users on Debian 13 / Ubuntu 24.04+ can install without dependency conflicts.

…>= 2.2

In pyscard 2.2.x, PCSCCardRequest.waitforcard() releases its internal
SCARD context before returning, leaving card_service.connection.hcontext
as None. The subsequent SCardConnect() call then fails with:

    TypeError: Expected a python long as SCARDCONTEXT.

This breaks peru-dnie on systems shipping recent pyscard, including
Debian 13 (python3-pyscard 2.2.2) with Python 3.13.

Fix: instead of returning card_service.connection directly, re-create
a fresh PCSCCardConnection from the reader. This establishes a new
SCARD context with a valid hcontext.

The PCSCCardConnection(reader) constructor API has been stable across
pyscard 2.0.x and 2.2.x, so this change is backward-compatible.

Tested on:
- Debian 13.4, Python 3.13, pyscard 2.2.2
- DNIe v2 (chip NXP JCOP3 SecID P60, applet RENIEC)
- Operations verified: extract signature, sign + openssl verify (Verified OK)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant