or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

atr-card-types.mdcard-connections.mdgui-components.mdindex.mdmonitoring.mdpcsc-interface.mdreader-management.mdsession-api.mdstatus-word-handling.mdutilities.md

pcsc-interface.mddocs/

0

# PC/SC Interface

1

2

Direct access to PC/SC (Personal Computer/Smart Card) functions and constants, providing complete control over smart card operations at the system level. This is the lowest-level API in pyscard.

3

4

## Capabilities

5

6

### Low-Level PC/SC Access

7

8

The scard module provides direct access to all PC/SC functions through a C extension module that wraps the native PC/SC libraries (WinSCard on Windows, PCSC-Lite on Unix-like systems).

9

10

```python { .api }

11

# Import all PC/SC functions and constants

12

from smartcard.scard import *

13

14

# Key PC/SC functions available:

15

def SCardEstablishContext(dwScope):

16

"""

17

Establish PC/SC context.

18

19

Args:

20

dwScope: Context scope (SCARD_SCOPE_USER, SCARD_SCOPE_TERMINAL, SCARD_SCOPE_SYSTEM)

21

22

Returns:

23

tuple: (result_code, context_handle)

24

"""

25

26

def SCardReleaseContext(hContext):

27

"""

28

Release PC/SC context.

29

30

Args:

31

hContext: Context handle from SCardEstablishContext

32

33

Returns:

34

int: Result code

35

"""

36

37

def SCardListReaders(hContext, mszGroups):

38

"""

39

List available smart card readers.

40

41

Args:

42

hContext: PC/SC context handle

43

mszGroups: Reader groups to query (None for all)

44

45

Returns:

46

tuple: (result_code, reader_list)

47

"""

48

49

def SCardConnect(hContext, szReader, dwShareMode, dwPreferredProtocols):

50

"""

51

Connect to smart card.

52

53

Args:

54

hContext: PC/SC context handle

55

szReader: Reader name

56

dwShareMode: Share mode (SCARD_SHARE_SHARED, SCARD_SHARE_EXCLUSIVE, etc.)

57

dwPreferredProtocols: Preferred protocols (SCARD_PROTOCOL_T0, SCARD_PROTOCOL_T1, etc.)

58

59

Returns:

60

tuple: (result_code, card_handle, active_protocol)

61

"""

62

63

def SCardDisconnect(hCard, dwDisposition):

64

"""

65

Disconnect from smart card.

66

67

Args:

68

hCard: Card handle from SCardConnect

69

dwDisposition: Disposition (SCARD_LEAVE_CARD, SCARD_RESET_CARD, etc.)

70

71

Returns:

72

int: Result code

73

"""

74

75

def SCardTransmit(hCard, pioSendPci, pbSendBuffer, pioRecvPci):

76

"""

77

Transmit APDU to smart card.

78

79

Args:

80

hCard: Card handle

81

pioSendPci: Send protocol info

82

pbSendBuffer: Command APDU bytes

83

pioRecvPci: Receive protocol info

84

85

Returns:

86

tuple: (result_code, response_bytes)

87

"""

88

89

def SCardGetStatusChange(hContext, dwTimeout, rgReaderStates):

90

"""

91

Wait for reader state changes.

92

93

Args:

94

hContext: PC/SC context handle

95

dwTimeout: Timeout in milliseconds (INFINITE for no timeout)

96

rgReaderStates: List of reader states to monitor

97

98

Returns:

99

tuple: (result_code, updated_reader_states)

100

"""

101

102

def SCardStatus(hCard):

103

"""

104

Get smart card status information.

105

106

Args:

107

hCard: Card handle

108

109

Returns:

110

tuple: (result_code, reader_name, state, protocol, atr)

111

"""

112

113

def SCardGetAttrib(hCard, dwAttrId):

114

"""

115

Get card/reader attribute.

116

117

Args:

118

hCard: Card handle

119

dwAttrId: Attribute identifier

120

121

Returns:

122

tuple: (result_code, attribute_data)

123

"""

124

125

def SCardControl(hCard, dwControlCode, pbSendBuffer):

126

"""

127

Send control command to reader.

128

129

Args:

130

hCard: Card handle

131

dwControlCode: Control code

132

pbSendBuffer: Control data

133

134

Returns:

135

tuple: (result_code, response_data)

136

"""

137

```

138

139

### PC/SC Constants

140

141

All PC/SC constants are available through the scard module import.

142

143

```python { .api }

144

# Context scope constants

145

SCARD_SCOPE_USER = 0

146

SCARD_SCOPE_TERMINAL = 1

147

SCARD_SCOPE_SYSTEM = 2

148

149

# Share mode constants

150

SCARD_SHARE_EXCLUSIVE = 1

151

SCARD_SHARE_SHARED = 2

152

SCARD_SHARE_DIRECT = 3

153

154

# Protocol constants

155

SCARD_PROTOCOL_UNDEFINED = 0

156

SCARD_PROTOCOL_T0 = 1

157

SCARD_PROTOCOL_T1 = 2

158

SCARD_PROTOCOL_RAW = 4

159

SCARD_PROTOCOL_T15 = 8

160

161

# Card state constants

162

SCARD_STATE_UNAWARE = 0x00

163

SCARD_STATE_IGNORE = 0x01

164

SCARD_STATE_CHANGED = 0x02

165

SCARD_STATE_UNKNOWN = 0x04

166

SCARD_STATE_UNAVAILABLE = 0x08

167

SCARD_STATE_EMPTY = 0x10

168

SCARD_STATE_PRESENT = 0x20

169

SCARD_STATE_ATRMATCH = 0x40

170

SCARD_STATE_EXCLUSIVE = 0x80

171

SCARD_STATE_INUSE = 0x100

172

SCARD_STATE_MUTE = 0x200

173

174

# Disposition constants

175

SCARD_LEAVE_CARD = 0

176

SCARD_RESET_CARD = 1

177

SCARD_UNPOWER_CARD = 2

178

SCARD_EJECT_CARD = 3

179

180

# Result codes

181

SCARD_S_SUCCESS = 0

182

SCARD_E_CANCELLED = 0x80100002

183

SCARD_E_INVALID_HANDLE = 0x80100003

184

SCARD_E_INVALID_PARAMETER = 0x80100004

185

SCARD_E_NO_MEMORY = 0x80100006

186

SCARD_E_TIMEOUT = 0x8010000A

187

SCARD_E_SHARING_VIOLATION = 0x8010000B

188

SCARD_E_NO_SMARTCARD = 0x8010000C

189

SCARD_E_UNKNOWN_CARD = 0x8010000D

190

SCARD_E_PROTO_MISMATCH = 0x8010000F

191

SCARD_E_NOT_READY = 0x80100010

192

SCARD_E_SYSTEM_CANCELLED = 0x80100012

193

SCARD_E_NOT_TRANSACTED = 0x80100016

194

SCARD_E_READER_UNAVAILABLE = 0x80100017

195

SCARD_W_UNSUPPORTED_CARD = 0x80100065

196

SCARD_W_UNRESPONSIVE_CARD = 0x80100066

197

SCARD_W_UNPOWERED_CARD = 0x80100067

198

SCARD_W_RESET_CARD = 0x80100068

199

SCARD_W_REMOVED_CARD = 0x80100069

200

201

# Timeout constants

202

INFINITE = 0xFFFFFFFF

203

204

# Attribute constants

205

SCARD_ATTR_VENDOR_NAME = 0x00010100

206

SCARD_ATTR_VENDOR_IFD_TYPE = 0x00010101

207

SCARD_ATTR_VENDOR_IFD_VERSION = 0x00010102

208

SCARD_ATTR_VENDOR_IFD_SERIAL_NO = 0x00010103

209

SCARD_ATTR_ATR_STRING = 0x00090303

210

SCARD_ATTR_ICC_PRESENCE = 0x00090300

211

```

212

213

## Usage Examples

214

215

### Basic PC/SC Operations

216

217

```python

218

from smartcard.scard import *

219

220

def basic_pcsc_example():

221

"""Demonstrate basic PC/SC operations."""

222

223

# Establish context

224

result, context = SCardEstablishContext(SCARD_SCOPE_USER)

225

if result != SCARD_S_SUCCESS:

226

print(f"Failed to establish context: {result:08X}")

227

return

228

229

print("✓ PC/SC context established")

230

231

try:

232

# List readers

233

result, readers = SCardListReaders(context, None)

234

if result != SCARD_S_SUCCESS:

235

print(f"Failed to list readers: {result:08X}")

236

return

237

238

print(f"Found {len(readers)} readers:")

239

for reader in readers:

240

print(f" {reader}")

241

242

if not readers:

243

print("No readers available")

244

return

245

246

# Connect to first reader

247

reader_name = readers[0]

248

result, card_handle, active_protocol = SCardConnect(

249

context, reader_name, SCARD_SHARE_SHARED,

250

SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1

251

)

252

253

if result != SCARD_S_SUCCESS:

254

print(f"Failed to connect to {reader_name}: {result:08X}")

255

return

256

257

print(f"✓ Connected to {reader_name}")

258

print(f"Active protocol: {active_protocol}")

259

260

try:

261

# Get card status

262

result, reader, state, protocol, atr = SCardStatus(card_handle)

263

if result == SCARD_S_SUCCESS:

264

print(f"Card status:")

265

print(f" Reader: {reader}")

266

print(f" State: {state:08X}")

267

print(f" Protocol: {protocol}")

268

print(f" ATR: {' '.join(f'{b:02X}' for b in atr)}")

269

270

# Transmit APDU (GET CHALLENGE)

271

if active_protocol == SCARD_PROTOCOL_T0:

272

send_pci = (SCARD_PROTOCOL_T0, 8)

273

else:

274

send_pci = (SCARD_PROTOCOL_T1, 8)

275

276

get_challenge = [0x00, 0x84, 0x00, 0x00, 0x08]

277

result, response = SCardTransmit(card_handle, send_pci, get_challenge, None)

278

279

if result == SCARD_S_SUCCESS:

280

print(f"GET CHALLENGE response: {' '.join(f'{b:02X}' for b in response)}")

281

else:

282

print(f"APDU transmission failed: {result:08X}")

283

284

finally:

285

# Disconnect

286

SCardDisconnect(card_handle, SCARD_LEAVE_CARD)

287

print("✓ Disconnected from card")

288

289

finally:

290

# Release context

291

SCardReleaseContext(context)

292

print("✓ PC/SC context released")

293

294

basic_pcsc_example()

295

```

296

297

### Reader State Monitoring

298

299

```python

300

from smartcard.scard import *

301

import time

302

303

def monitor_reader_states(duration=30):

304

"""Monitor reader state changes using PC/SC."""

305

306

result, context = SCardEstablishContext(SCARD_SCOPE_USER)

307

if result != SCARD_S_SUCCESS:

308

print(f"Context establishment failed: {result:08X}")

309

return

310

311

try:

312

# Get initial reader list

313

result, readers = SCardListReaders(context, None)

314

if result != SCARD_S_SUCCESS or not readers:

315

print("No readers available")

316

return

317

318

print(f"Monitoring {len(readers)} readers for {duration} seconds")

319

320

# Initialize reader states

321

reader_states = []

322

for reader in readers:

323

reader_states.append({

324

'reader': reader,

325

'current_state': SCARD_STATE_UNAWARE,

326

'event_state': SCARD_STATE_UNAWARE,

327

'atr': []

328

})

329

330

start_time = time.time()

331

while time.time() - start_time < duration:

332

# Wait for state changes (1 second timeout)

333

result, updated_states = SCardGetStatusChange(context, 1000, reader_states)

334

335

if result == SCARD_S_SUCCESS:

336

for i, state in enumerate(updated_states):

337

old_state = reader_states[i]['current_state']

338

new_state = state['event_state']

339

340

if new_state != old_state:

341

reader_name = state['reader']

342

print(f"\n{reader_name}:")

343

print(f" State change: {old_state:08X} -> {new_state:08X}")

344

345

# Analyze state flags

346

if new_state & SCARD_STATE_PRESENT:

347

print(" ✓ Card present")

348

if state['atr']:

349

atr_str = ' '.join(f'{b:02X}' for b in state['atr'])

350

print(f" ATR: {atr_str}")

351

elif new_state & SCARD_STATE_EMPTY:

352

print(" ✗ Card removed")

353

354

if new_state & SCARD_STATE_EXCLUSIVE:

355

print(" ⚠ Exclusive access")

356

if new_state & SCARD_STATE_INUSE:

357

print(" ⚠ In use")

358

if new_state & SCARD_STATE_MUTE:

359

print(" ⚠ Mute card")

360

361

# Update current state for next iteration

362

reader_states[i]['current_state'] = new_state

363

364

elif result != SCARD_E_TIMEOUT:

365

print(f"State monitoring error: {result:08X}")

366

break

367

368

finally:

369

SCardReleaseContext(context)

370

371

monitor_reader_states(15)

372

```

373

374

### Advanced PC/SC Operations

375

376

```python

377

from smartcard.scard import *

378

379

def advanced_pcsc_operations():

380

"""Demonstrate advanced PC/SC features."""

381

382

result, context = SCardEstablishContext(SCARD_SCOPE_SYSTEM)

383

if result != SCARD_S_SUCCESS:

384

print(f"Context failed: {result:08X}")

385

return

386

387

try:

388

result, readers = SCardListReaders(context, None)

389

if result != SCARD_S_SUCCESS or not readers:

390

return

391

392

reader_name = readers[0]

393

394

# Connect in direct mode for reader control

395

result, card_handle, protocol = SCardConnect(

396

context, reader_name, SCARD_SHARE_DIRECT, 0

397

)

398

399

if result != SCARD_S_SUCCESS:

400

print(f"Direct connection failed: {result:08X}")

401

return

402

403

try:

404

# Get reader attributes

405

attributes = [

406

(SCARD_ATTR_VENDOR_NAME, "Vendor Name"),

407

(SCARD_ATTR_VENDOR_IFD_TYPE, "Reader Type"),

408

(SCARD_ATTR_VENDOR_IFD_VERSION, "Reader Version"),

409

(SCARD_ATTR_VENDOR_IFD_SERIAL_NO, "Serial Number")

410

]

411

412

print(f"Reader: {reader_name}")

413

print("Attributes:")

414

415

for attr_id, attr_name in attributes:

416

result, attr_data = SCardGetAttrib(card_handle, attr_id)

417

if result == SCARD_S_SUCCESS:

418

if attr_name in ["Vendor Name", "Reader Type"]:

419

# Convert to string (remove null terminators)

420

try:

421

attr_str = bytes(attr_data).decode('ascii').rstrip('\x00')

422

print(f" {attr_name}: {attr_str}")

423

except:

424

print(f" {attr_name}: {attr_data}")

425

else:

426

print(f" {attr_name}: {' '.join(f'{b:02X}' for b in attr_data)}")

427

else:

428

print(f" {attr_name}: Not available ({result:08X})")

429

430

# Try reader-specific control commands (example for CCID readers)

431

# Note: Control codes are reader-specific

432

try:

433

# Example: Get reader features (CCID)

434

control_code = 0x42000D48 # IOCTL_SMARTCARD_GET_FEATURE_REQUEST

435

result, features = SCardControl(card_handle, control_code, [])

436

if result == SCARD_S_SUCCESS:

437

print(f"Reader features: {len(features)} bytes")

438

print(f" Data: {' '.join(f'{b:02X}' for b in features)}")

439

except:

440

print(" Control commands not supported or failed")

441

442

finally:

443

SCardDisconnect(card_handle, SCARD_LEAVE_CARD)

444

445

finally:

446

SCardReleaseContext(context)

447

448

advanced_pcsc_operations()

449

```

450

451

### Error Handling and Result Codes

452

453

```python

454

from smartcard.scard import *

455

456

def error_code_analysis():

457

"""Demonstrate PC/SC error handling."""

458

459

# Common result codes and their meanings

460

error_codes = {

461

SCARD_S_SUCCESS: "Success",

462

SCARD_E_CANCELLED: "Cancelled",

463

SCARD_E_INVALID_HANDLE: "Invalid handle",

464

SCARD_E_INVALID_PARAMETER: "Invalid parameter",

465

SCARD_E_NO_MEMORY: "No memory",

466

SCARD_E_TIMEOUT: "Timeout",

467

SCARD_E_SHARING_VIOLATION: "Sharing violation",

468

SCARD_E_NO_SMARTCARD: "No smart card",

469

SCARD_E_UNKNOWN_CARD: "Unknown card",

470

SCARD_E_PROTO_MISMATCH: "Protocol mismatch",

471

SCARD_E_NOT_READY: "Not ready",

472

SCARD_E_SYSTEM_CANCELLED: "System cancelled",

473

SCARD_E_NOT_TRANSACTED: "Not transacted",

474

SCARD_E_READER_UNAVAILABLE: "Reader unavailable",

475

SCARD_W_UNSUPPORTED_CARD: "Warning: Unsupported card",

476

SCARD_W_UNRESPONSIVE_CARD: "Warning: Unresponsive card",

477

SCARD_W_UNPOWERED_CARD: "Warning: Unpowered card",

478

SCARD_W_RESET_CARD: "Warning: Reset card",

479

SCARD_W_REMOVED_CARD: "Warning: Removed card"

480

}

481

482

def interpret_result(result_code):

483

"""Interpret PC/SC result code."""

484

if result_code in error_codes:

485

return error_codes[result_code]

486

elif result_code & 0x80000000:

487

return f"Error: {result_code:08X}"

488

else:

489

return f"Success/Warning: {result_code:08X}"

490

491

# Test various scenarios

492

print("PC/SC Error Code Analysis:")

493

494

# Try to establish context

495

result, context = SCardEstablishContext(SCARD_SCOPE_USER)

496

print(f"Context: {interpret_result(result)}")

497

498

if result == SCARD_S_SUCCESS:

499

# Try invalid reader

500

result, card, protocol = SCardConnect(

501

context, "NonexistentReader", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0

502

)

503

print(f"Invalid reader: {interpret_result(result)}")

504

505

# Try with no timeout

506

result, states = SCardGetStatusChange(context, 0, [])

507

print(f"Zero timeout: {interpret_result(result)}")

508

509

SCardReleaseContext(context)

510

511

error_code_analysis()

512

```

513

514

## Related Types

515

516

```python { .api }

517

# PC/SC handle types

518

ContextHandle = int

519

CardHandle = int

520

521

# PC/SC data structures

522

ReaderState = dict # {'reader': str, 'current_state': int, 'event_state': int, 'atr': list[int]}

523

ProtocolInfo = tuple[int, int] # (protocol, pci_length)

524

525

# Result code type

526

ResultCode = int

527

528

# Common PC/SC constants (subset - full list available via import)

529

ScopeType = int # SCARD_SCOPE_* constants

530

ShareMode = int # SCARD_SHARE_* constants

531

Protocol = int # SCARD_PROTOCOL_* constants

532

Disposition = int # SCARD_*_CARD constants

533

StateFlag = int # SCARD_STATE_* constants

534

AttributeId = int # SCARD_ATTR_* constants

535

```