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

status-word-handling.mddocs/

0

# Status Word Handling

1

2

Structured error checking and exception handling for smart card status words (SW1, SW2) with support for various ISO standards and custom error checking chains. Status words indicate the result of APDU command execution.

3

4

## Capabilities

5

6

### Status Word Exceptions

7

8

Exception hierarchy for handling different categories of smart card status word errors.

9

10

```python { .api }

11

class SWException(SmartcardException):

12

"""

13

Base exception for smart card status word errors.

14

15

Args:

16

data (list[int]): Response data from APDU

17

sw1 (int): First status word byte (0x00-0xFF)

18

sw2 (int): Second status word byte (0x00-0xFF)

19

"""

20

21

class WarningProcessingException(SWException):

22

"""

23

Non-volatile memory unchanged (SW1=62) or corrupted (SW1=63).

24

Indicates warnings during command processing.

25

"""

26

27

class ExecutionErrorException(SWException):

28

"""

29

Non-volatile memory changed (SW1=64) or unchanged (SW1=65).

30

Indicates execution errors during command processing.

31

"""

32

33

class SecurityRelatedException(SWException):

34

"""

35

Security-related errors (SW1=66).

36

Indicates authentication or access control failures.

37

"""

38

39

class CheckingErrorException(SWException):

40

"""

41

Wrong length or instruction errors (SW1=67-6F).

42

Indicates parameter or command format errors.

43

"""

44

```

45

46

### Error Checker Classes

47

48

Base classes and implementations for checking status words and raising appropriate exceptions.

49

50

```python { .api }

51

class ErrorChecker:

52

"""Abstract base class for status word error checking. Concrete implementations include ISO7816_4ErrorChecker, ISO7816_8ErrorChecker, and ISO7816_9ErrorChecker."""

53

54

def __call__(self, data, sw1, sw2):

55

"""

56

Check status words and raise exception if error detected.

57

58

Args:

59

data (list[int]): Response data from APDU

60

sw1 (int): First status word byte

61

sw2 (int): Second status word byte

62

63

Raises:

64

SWException: If error condition is detected

65

"""

66

67

class ISO7816_4ErrorChecker(ErrorChecker):

68

"""Error checker for ISO 7816-4 status words."""

69

70

class ISO7816_4_SW1ErrorChecker(ErrorChecker):

71

"""Error checker focusing on SW1 values per ISO 7816-4."""

72

73

class ISO7816_8ErrorChecker(ErrorChecker):

74

"""Error checker for ISO 7816-8 (cryptographic) status words."""

75

76

class ISO7816_9ErrorChecker(ErrorChecker):

77

"""Error checker for ISO 7816-9 (enhanced cryptographic) status words."""

78

79

class op21_ErrorChecker(ErrorChecker):

80

"""Error checker for Open Platform 2.1 status words."""

81

```

82

83

### Error Checking Chain

84

85

Mechanism for combining multiple error checkers in a processing chain.

86

87

```python { .api }

88

class ErrorCheckingChain:

89

"""Chain multiple error checkers for comprehensive status word analysis."""

90

91

def __init__(self, chain, strategy):

92

"""

93

Initialize error checking chain.

94

95

Args:

96

chain (list): List to append this error checker to

97

strategy (ErrorChecker): Error checking strategy to add to chain

98

"""

99

100

def addErrorChecker(self, errorchecker):

101

"""

102

Add an error checker to the chain.

103

104

Args:

105

errorchecker (ErrorChecker): Error checker to add

106

"""

107

108

def removeErrorChecker(self, errorchecker):

109

"""

110

Remove an error checker from the chain.

111

112

Args:

113

errorchecker (ErrorChecker): Error checker to remove

114

"""

115

116

def __call__(self, data, sw1, sw2):

117

"""

118

Execute all error checkers in the chain.

119

120

Args:

121

data (list[int]): Response data

122

sw1 (int): First status word

123

sw2 (int): Second status word

124

125

Raises:

126

SWException: If any checker detects an error

127

"""

128

```

129

130

## Usage Examples

131

132

### Basic Status Word Checking

133

134

```python

135

from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker

136

from smartcard.sw.SWExceptions import SWException

137

from smartcard import Session

138

139

def check_apdu_response(command, session):

140

"""Send APDU and check status words."""

141

142

# Create error checker

143

error_checker = ISO7816_4ErrorChecker()

144

145

try:

146

# Send command

147

response, sw1, sw2 = session.sendCommandAPDU(command)

148

149

# Check for errors

150

error_checker(response, sw1, sw2)

151

152

print(f"✓ Command successful: {sw1:02X} {sw2:02X}")

153

return response

154

155

except SWException as e:

156

print(f"✗ Status word error: {e}")

157

print(f" SW1 SW2: {e.sw1:02X} {e.sw2:02X}")

158

if hasattr(e, 'data') and e.data:

159

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

160

raise

161

162

# Example usage

163

try:

164

session = Session()

165

166

# Valid command (should succeed)

167

SELECT_MF = [0x00, 0xA4, 0x00, 0x00]

168

response = check_apdu_response(SELECT_MF, session)

169

170

# Invalid command (will likely fail)

171

INVALID_CMD = [0xFF, 0xFF, 0xFF, 0xFF]

172

response = check_apdu_response(INVALID_CMD, session)

173

174

session.close()

175

176

except Exception as e:

177

print(f"Session error: {e}")

178

```

179

180

### Error Checking Chain

181

182

```python

183

from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain

184

from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker

185

from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker

186

from smartcard.sw.SWExceptions import *

187

from smartcard import Session

188

189

def comprehensive_error_checking():

190

"""Demonstrate error checking chain usage."""

191

192

# Create error checking chain

193

chain = ErrorCheckingChain()

194

chain.addErrorChecker(ISO7816_4ErrorChecker())

195

chain.addErrorChecker(ISO7816_8ErrorChecker())

196

197

session = Session()

198

199

commands = [

200

([0x00, 0xA4, 0x00, 0x00], "SELECT Master File"),

201

([0x00, 0xCA, 0x9F, 0x7F, 0x00], "GET DATA"),

202

([0x00, 0x84, 0x00, 0x00, 0x08], "GET CHALLENGE"),

203

([0xFF, 0xFF, 0xFF, 0xFF], "Invalid Command")

204

]

205

206

for command, description in commands:

207

try:

208

print(f"\nTesting: {description}")

209

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

210

211

response, sw1, sw2 = session.sendCommandAPDU(command)

212

213

# Apply error checking chain

214

chain(response, sw1, sw2)

215

216

print(f"✓ Success: {sw1:02X} {sw2:02X}")

217

if response:

218

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

219

220

except WarningProcessingException as e:

221

print(f"⚠ Warning: {e}")

222

except ExecutionErrorException as e:

223

print(f"✗ Execution Error: {e}")

224

except SecurityRelatedException as e:

225

print(f"🔒 Security Error: {e}")

226

except CheckingErrorException as e:

227

print(f"📋 Parameter Error: {e}")

228

except SWException as e:

229

print(f"❌ Status Word Error: {e}")

230

231

session.close()

232

233

comprehensive_error_checking()

234

```

235

236

### Custom Error Checker

237

238

```python

239

from smartcard.sw.ErrorChecker import ErrorChecker

240

from smartcard.sw.SWExceptions import SWException

241

242

class CustomApplicationException(SWException):

243

"""Custom exception for application-specific errors."""

244

pass

245

246

class ApplicationErrorChecker(ErrorChecker):

247

"""Custom error checker for application-specific status words."""

248

249

def __call__(self, data, sw1, sw2):

250

# Check for application-specific error patterns

251

252

# Example: Custom application returns 0x90 0x01 for partial success

253

if sw1 == 0x90 and sw2 == 0x01:

254

raise CustomApplicationException(

255

data, sw1, sw2,

256

"Partial success - some data may be incomplete"

257

)

258

259

# Example: Application-specific authentication error

260

if sw1 == 0x63 and 0xC0 <= sw2 <= 0xCF:

261

remaining_tries = sw2 & 0x0F

262

raise CustomApplicationException(

263

data, sw1, sw2,

264

f"Authentication failed - {remaining_tries} tries remaining"

265

)

266

267

# Example: Application-specific file errors

268

if sw1 == 0x94:

269

error_messages = {

270

0x00: "No current EF",

271

0x02: "Address range exceeded",

272

0x04: "File ID not found",

273

0x08: "File incompatible with command"

274

}

275

message = error_messages.get(sw2, f"File error: {sw2:02X}")

276

raise CustomApplicationException(data, sw1, sw2, message)

277

278

def test_custom_error_checker():

279

"""Test custom error checker implementation."""

280

281

checker = ApplicationErrorChecker()

282

283

test_cases = [

284

([], 0x90, 0x00, "Should pass"),

285

([], 0x90, 0x01, "Partial success"),

286

([], 0x63, 0xC3, "Auth failed, 3 tries left"),

287

([], 0x94, 0x04, "File not found"),

288

([], 0x94, 0xFF, "Unknown file error")

289

]

290

291

for data, sw1, sw2, description in test_cases:

292

try:

293

print(f"\nTesting: {description} ({sw1:02X} {sw2:02X})")

294

checker(data, sw1, sw2)

295

print("✓ No error detected")

296

297

except CustomApplicationException as e:

298

print(f"🔍 Custom error: {e}")

299

except Exception as e:

300

print(f"❌ Unexpected error: {e}")

301

302

test_custom_error_checker()

303

```

304

305

### Connection-Level Error Checking

306

307

```python

308

from smartcard.CardRequest import CardRequest

309

from smartcard.CardType import AnyCardType

310

from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain

311

from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker

312

313

def connection_with_error_checking():

314

"""Demonstrate setting error checking at connection level."""

315

316

# Wait for card

317

cardrequest = CardRequest(timeout=10, cardType=AnyCardType())

318

319

try:

320

cardservice = cardrequest.waitforcard()

321

322

with cardservice:

323

connection = cardservice.connection

324

325

# Set up error checking chain for this connection

326

error_chain = ErrorCheckingChain()

327

error_chain.addErrorChecker(ISO7816_4ErrorChecker())

328

connection.setErrorCheckingChain(error_chain)

329

330

print("Error checking enabled for connection")

331

332

# Now all transmit operations will automatically check status words

333

try:

334

# This will automatically check status words

335

response, sw1, sw2 = connection.transmit([0x00, 0xA4, 0x00, 0x00])

336

print(f"✓ SELECT successful: {sw1:02X} {sw2:02X}")

337

338

# This might fail and raise an exception automatically

339

response, sw1, sw2 = connection.transmit([0xFF, 0xFF, 0xFF, 0xFF])

340

print(f"✓ Invalid command succeeded: {sw1:02X} {sw2:02X}")

341

342

except Exception as e:

343

print(f"🚫 Connection error checking caught: {e}")

344

345

except Exception as e:

346

print(f"Card request failed: {e}")

347

348

connection_with_error_checking()

349

```

350

351

### Status Word Analysis

352

353

```python

354

def analyze_status_words(sw1, sw2):

355

"""Analyze and explain status word meanings."""

356

357

print(f"Status Words: {sw1:02X} {sw2:02X}")

358

359

# Success cases

360

if sw1 == 0x90 and sw2 == 0x00:

361

print("✓ Success - Command completed successfully")

362

return

363

364

if sw1 == 0x61:

365

print(f"✓ Success - {sw2} bytes available with GET RESPONSE")

366

return

367

368

# Warning cases (SW1 = 62, 63)

369

if sw1 == 0x62:

370

warnings = {

371

0x00: "No information given (NV-RAM not changed)",

372

0x81: "Part of returned data may be corrupted",

373

0x82: "End of file/record reached before reading Le bytes",

374

0x83: "Selected file invalidated",

375

0x84: "Selected file is not valid (FCI not formated)"

376

}

377

msg = warnings.get(sw2, f"Warning: Non-volatile memory unchanged ({sw2:02X})")

378

print(f"⚠ {msg}")

379

380

elif sw1 == 0x63:

381

if 0xC0 <= sw2 <= 0xCF:

382

tries = sw2 & 0x0F

383

print(f"⚠ Authentication failed - {tries} tries remaining")

384

else:

385

warnings = {

386

0x00: "No information given (NV-RAM changed)",

387

0x81: "File filled up by the last write"

388

}

389

msg = warnings.get(sw2, f"Warning: Non-volatile memory changed ({sw2:02X})")

390

print(f"⚠ {msg}")

391

392

# Error cases (SW1 = 64, 65, 66, 67-6F)

393

elif sw1 == 0x64:

394

print(f"❌ Execution error: Non-volatile memory changed ({sw2:02X})")

395

396

elif sw1 == 0x65:

397

print(f"❌ Execution error: Non-volatile memory unchanged ({sw2:02X})")

398

399

elif sw1 == 0x66:

400

print(f"🔒 Security error: {sw2:02X}")

401

402

elif 0x67 <= sw1 <= 0x6F:

403

error_types = {

404

0x67: "Wrong length",

405

0x68: "Function in CLA not supported",

406

0x69: "Command not allowed",

407

0x6A: "Wrong parameters P1-P2",

408

0x6B: "Wrong parameters P1-P2",

409

0x6C: f"Wrong Le field (correct length: {sw2})",

410

0x6D: "Instruction code not supported",

411

0x6E: "Class not supported",

412

0x6F: "No precise diagnosis"

413

}

414

error_msg = error_types.get(sw1, f"Parameter error ({sw1:02X})")

415

print(f"📋 {error_msg}: {sw2:02X}")

416

417

else:

418

print(f"❓ Unknown status words: {sw1:02X} {sw2:02X}")

419

420

# Test status word analysis

421

test_status_words = [

422

(0x90, 0x00), (0x61, 0x10), (0x62, 0x83), (0x63, 0xC2),

423

(0x64, 0x00), (0x66, 0x00), (0x67, 0x00), (0x6C, 0x08),

424

(0x6D, 0x00), (0x6E, 0x00), (0x9F, 0x10)

425

]

426

427

print("Status Word Analysis:")

428

for sw1, sw2 in test_status_words:

429

print()

430

analyze_status_words(sw1, sw2)

431

```

432

433

## Related Types

434

435

```python { .api }

436

# Exception hierarchy

437

class SmartcardException(Exception):

438

"""Base exception for smartcard operations."""

439

440

class SWException(SmartcardException):

441

"""Base class for status word exceptions."""

442

def __init__(self, data, sw1, sw2, message=""):

443

self.data = data

444

self.sw1 = sw1

445

self.sw2 = sw2

446

447

# Type aliases

448

StatusWord = int # SW1 or SW2 (0x00-0xFF)

449

ResponseData = list[int] # APDU response data

450

ErrorChecker = callable # Function/class that checks status words

451

```