Check-in [330efa4f3b]
Overview
Comment:Updated ignores

Updated read_tlv to return a list

Added a free_tlv function

Updated value->str conversion functions to be more flexible/direct

Added sample code to select all PKI applets/files

Simplified TLV entity

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 330efa4f3bb6e0e6f40dd55c33bb6290ff0e41d1
User & Date: rkeene on 2010-05-12 19:35:41
Other Links: manifest | tags
Context
2010-05-12
21:52
Added routines for reading certificates

Updated OpenSession to use PC/SC certificates

Comment and debugging update

Updated to read in larger chunks to improve speed check-in: 06e07b8f0d user: rkeene tags: trunk

19:35
Updated ignores

Updated read_tlv to return a list

Added a free_tlv function

Updated value->str conversion functions to be more flexible/direct

Added sample code to select all PKI applets/files

Simplified TLV entity check-in: 330efa4f3b user: rkeene tags: trunk

17:25
Updated PC/SC error messages to include text return value as well as numeric value

Minor reorganization check-in: 2d8b4030f7 user: rkeene tags: trunk

Changes

Modified cackey.c from [d5b94d106d] to [e9e3a11241].

172
173
174
175
176
177
178
179
180
181
182
183

184
185
186

187
188
189

190
191
192

193
194
195

196
197
198

199
200
201

202
203
204

205
206
207

208
209
210

211
212
213

214
215
216

217
218
219

220
221
222

223
224
225

226
227
228

229
230
231

232
233
234

235
236
237

238
239
240

241
242
243

244
245
246

247
248
249

250
251
252

253
254
255

256
257
258

259
260
261

262
263
264

265
266
267

268
269
270

271
272
273

274
275
276

277
278
279

280
281
282

283
284
285

286
287
288

289
290
291

292
293
294

295
296
297

298
299
300

301
302
303

304
305
306

307
308
309

310
311
312

313
314
315

316
317
318

319
320
321

322
323
324

325
326
327

328
329
330

331
332
333

334
335
336
337
338

339
340
341
342
343
344
345
346
347
348
349

350
351
352

353
354
355

356
357
358

359
360
361

362
363
364

365
366
367

368
369
370

371
372
373

374
375
376

377
378
379

380
381
382

383
384
385

386
387
388

389
390
391

392
393
394

395
396
397

398
399
400

401
402
403

404
405
406

407
408
409

410
411
412

413
414
415

416
417
418

419
420
421

422
423
424

425
426
427

428
429
430

431
432
433

434
435
436

437
438
439

440
441
442

443
444
445

446
447
448
449
450

451
452




























453






















454
455
456
457
458
459
460
461
462
463


464
465
466
467
468
469
470
172
173
174
175
176
177
178


179
180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282
283


284



285
286
287


288
289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355
356


357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428







-
-


-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-


-
-
+
-
-
-



-
-


-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-

-
+
-


-
-
+


+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+










+
+







		fprintf(stderr, "\n");
	}

	return(retval);
}

static const char *CACKEY_DEBUG_FUNC_TAG_TO_STR(unsigned char tag) {
	const char *retval = NULL;

	switch (tag) {
		case GSCIS_TAG_CARDID:
			retval = "GSCIS_TAG_CARDID";
			return("GSCIS_TAG_CARDID");
			break;
		case GSCIS_TAG_CCC_VER:
			retval = "GSCIS_TAG_CCC_VER";
			return("GSCIS_TAG_CCC_VER");
			break;
		case GSCIS_TAG_CCG_VER:
			retval = "GSCIS_TAG_CCG_VER";
			return("GSCIS_TAG_CCG_VER");
			break;
		case GSCIS_TAG_CARDURL:
			retval = "GSCIS_TAG_CARDURL";
			return("GSCIS_TAG_CARDURL");
			break;
		case GSCIS_TAG_PKCS15:
			retval = "GSCIS_TAG_PKCS15";
			return("GSCIS_TAG_PKCS15");
			break;
		case GSCIS_TAG_REG_DATA_MODEL:
			retval = "GSCIS_TAG_REG_DATA_MODEL";
			return("GSCIS_TAG_REG_DATA_MODEL");
			break;
		case GSCIS_TAG_ACR_TABLE:
			retval = "GSCIS_TAG_ACR_TABLE";
			return("GSCIS_TAG_ACR_TABLE");
			break;
		case GSCIS_TAG_CARD_APDU:
			retval = "GSCIS_TAG_CARD_APDU";
			return("GSCIS_TAG_CARD_APDU");
			break;
		case GSCIS_TAG_REDIRECTION:
			retval = "GSCIS_TAG_REDIRECTION";
			return("GSCIS_TAG_REDIRECTION");
			break;
		case GSCIS_TAG_CT:
			retval = "GSCIS_TAG_CT";
			return("GSCIS_TAG_CT");
			break;
		case GSCIS_TAG_ST:
			retval = "GSCIS_TAG_ST";
			return("GSCIS_TAG_ST");
			break;
		case GSCIS_TAG_NEXTCCC:
			retval = "GSCIS_TAG_NEXTCCC";
			return("GSCIS_TAG_NEXTCCC");
			break;
		case GSCIS_TAG_FNAME:
			retval = "GSCIS_TAG_FNAME";
			return("GSCIS_TAG_FNAME");
			break;
		case GSCIS_TAG_MNAME:
			retval = "GSCIS_TAG_MNAME";
			return("GSCIS_TAG_MNAME");
			break;
		case GSCIS_TAG_LNAME:
			retval = "GSCIS_TAG_LNAME";
			return("GSCIS_TAG_LNAME");
			break;
		case GSCIS_TAG_SUFFIX:
			retval = "GSCIS_TAG_SUFFIX";
			return("GSCIS_TAG_SUFFIX");
			break;
		case GSCIS_TAG_GOVT_AGENCY:
			retval = "GSCIS_TAG_GOVT_AGENCY";
			return("GSCIS_TAG_GOVT_AGENCY");
			break;
		case GSCIS_TAG_BUREAU:
			retval = "GSCIS_TAG_BUREAU";
			return("GSCIS_TAG_BUREAU");
			break;
		case GSCIS_TAG_BUREAU_CODE:
			retval = "GSCIS_TAG_BUREAU_CODE";
			return("GSCIS_TAG_BUREAU_CODE");
			break;
		case GSCIS_TAG_DEPT_CODE:
			retval = "GSCIS_TAG_DEPT_CODE";
			return("GSCIS_TAG_DEPT_CODE");
			break;
		case GSCIS_TAG_TITLE:
			retval = "GSCIS_TAG_TITLE";
			return("GSCIS_TAG_TITLE");
			break;
		case GSCIS_TAG_BUILDING:
			retval = "GSCIS_TAG_BUILDING";
			return("GSCIS_TAG_BUILDING");
			break;
		case GSCIS_TAG_OFFICE_ADDR1:
			retval = "GSCIS_TAG_OFFICE_ADDR1";
			return("GSCIS_TAG_OFFICE_ADDR1");
			break;
		case GSCIS_TAG_OFFICE_ADDR2:
			retval = "GSCIS_TAG_OFFICE_ADDR2";
			return("GSCIS_TAG_OFFICE_ADDR2");
			break;
		case GSCIS_TAG_OFFICE_CITY:
			retval = "GSCIS_TAG_OFFICE_CITY";
			return("GSCIS_TAG_OFFICE_CITY");
			break;
		case GSCIS_TAG_OFFICE_STATE:
			retval = "GSCIS_TAG_OFFICE_STATE";
			return("GSCIS_TAG_OFFICE_STATE");
			break;
		case GSCIS_TAG_OFFICE_ZIP:
			retval = "GSCIS_TAG_OFFICE_ZIP";
			return("GSCIS_TAG_OFFICE_ZIP");
			break;
		case GSCIS_TAG_OFFICE_COUNTRY:
			retval = "GSCIS_TAG_OFFICE_COUNTRY";
			return("GSCIS_TAG_OFFICE_COUNTRY");
			break;
		case GSCIS_TAG_OFFICE_PHONE:
			retval = "GSCIS_TAG_OFFICE_PHONE";
			return("GSCIS_TAG_OFFICE_PHONE");
			break;
		case GSCIS_TAG_OFFICE_PHONE_EXT:
			retval = "GSCIS_TAG_OFFICE_PHONE_EXT";
			return("GSCIS_TAG_OFFICE_PHONE_EXT");
			break;
		case GSCIS_TAG_OFFICE_FAX:
			retval = "GSCIS_TAG_OFFICE_FAX";
			return("GSCIS_TAG_OFFICE_FAX");
			break;
		case GSCIS_TAG_OFFICE_EMAIL:
			retval = "GSCIS_TAG_OFFICE_EMAIL";
			return("GSCIS_TAG_OFFICE_EMAIL");
			break;
		case GSCIS_TAG_OFFICE_ROOM:
			retval = "GSCIS_TAG_OFFICE_ROOM";
			return("GSCIS_TAG_OFFICE_ROOM");
			break;
		case GSCIS_TAG_NONGOV_AGENCY:
			retval = "GSCIS_TAG_NONGOV_AGENCY";
			return("GSCIS_TAG_NONGOV_AGENCY");
			break;
		case GSCIS_TAG_SSN_DESIGNATOR:
			retval = "GSCIS_TAG_SSN_DESIGNATOR";
			return("GSCIS_TAG_SSN_DESIGNATOR");
			break;
		case GSCIS_TAG_SSN:
			retval = "GSCIS_TAG_SSN";
			return("GSCIS_TAG_SSN");
			break;
		case GSCIS_TAG_DOB:
			retval = "GSCIS_TAG_DOB";
			return("GSCIS_TAG_DOB");
			break;
		case GSCIS_TAG_GENDER:
			retval = "GSCIS_TAG_GENDER";
			return("GSCIS_TAG_GENDER");
			break;
		case GSCIS_TAG_USERID:
			retval = "GSCIS_TAG_USERID";
			return("GSCIS_TAG_USERID");
			break;
		case GSCIS_TAG_DOMAIN:
			retval = "GSCIS_TAG_DOMAIN";
			return("GSCIS_TAG_DOMAIN");
			break;
		case GSCIS_TAG_PASSWORD:
			retval = "GSCIS_TAG_PASSWORD";
			return("GSCIS_TAG_PASSWORD");
			break;
		case GSCIS_TAG_ISSUERID:
			retval = "GSCIS_TAG_ISSUERID";
			return("GSCIS_TAG_ISSUERID");
			break;
		case GSCIS_TAG_SERNO:
			retval = "GSCIS_TAG_SERNO";
			return("GSCIS_TAG_SERNO");
			break;
		case GSCIS_TAG_ISSUE_DATE:
			retval = "GSCIS_TAG_ISSUE_DATE";
			return("GSCIS_TAG_ISSUE_DATE");
			break;
		case GSCIS_TAG_EXPIRE_DATE:
			retval = "GSCIS_TAG_EXPIRE_DATE";
			return("GSCIS_TAG_EXPIRE_DATE");
			break;
		case GSCIS_TAG_CARD_TYPE:
			retval = "GSCIS_TAG_CARD_TYPE";
			return("GSCIS_TAG_CARD_TYPE");
			break;
		case GSCIS_TAG_SECURITY_CODE:
			retval = "GSCIS_TAG_SECURITY_CODE";
			return("GSCIS_TAG_SECURITY_CODE");
			break;
		case GSCIS_TAG_CARDID_AID:
			retval = "GSCIS_TAG_CARDID_AID";
			return("GSCIS_TAG_CARDID_AID");
			break;
		case GSCIS_TAG_CERTIFICATE:
			retval = "GSCIS_TAG_CERTIFICATE";
			return("GSCIS_TAG_CERTIFICATE");
			break;
		case GSCIS_TAG_CERT_ISSUE_DATE:
			retval = "GSCIS_TAG_CERT_ISSUE_DATE";
			return("GSCIS_TAG_CERT_ISSUE_DATE");
			break;
		case GSCIS_TAG_CERT_EXPIRE_DATE:
			retval = "GSCIS_TAG_CERT_EXPIRE_DATE";
			return("GSCIS_TAG_CERT_EXPIRE_DATE");
			break;
	}

	if (retval == NULL) {
		retval = "UNKNOWN";
	return("UNKNOWN");
	}

	return(retval);
}

static const char *CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(LONG retcode) {
	const char *retval = NULL;

	switch (retcode) {
		case SCARD_S_SUCCESS:
			retval = "SCARD_S_SUCCESS";
			return("SCARD_S_SUCCESS");
			break;
		case SCARD_E_CANCELLED:
			retval = "SCARD_E_CANCELLED";
			return("SCARD_E_CANCELLED");
			break;
		case SCARD_E_CANT_DISPOSE:
			retval = "SCARD_E_CANT_DISPOSE";
			return("SCARD_E_CANT_DISPOSE");
			break;
		case SCARD_E_INSUFFICIENT_BUFFER:
			retval = "SCARD_E_INSUFFICIENT_BUFFER";
			return("SCARD_E_INSUFFICIENT_BUFFER");
			break;
		case SCARD_E_INVALID_ATR:
			retval = "SCARD_E_INVALID_ATR";
			return("SCARD_E_INVALID_ATR");
			break;
		case SCARD_E_INVALID_HANDLE:
			retval = "SCARD_E_INVALID_HANDLE";
			return("SCARD_E_INVALID_HANDLE");
			break;
		case SCARD_E_INVALID_PARAMETER:
			retval = "SCARD_E_INVALID_PARAMETER";
			return("SCARD_E_INVALID_PARAMETER");
			break;
		case SCARD_E_INVALID_TARGET:
			retval = "SCARD_E_INVALID_TARGET";
			return("SCARD_E_INVALID_TARGET");
			break;
		case SCARD_E_INVALID_VALUE:
			retval = "SCARD_E_INVALID_VALUE";
			return("SCARD_E_INVALID_VALUE");
			break;
		case SCARD_E_NO_MEMORY:
			retval = "SCARD_E_NO_MEMORY";
			return("SCARD_E_NO_MEMORY");
			break;
		case SCARD_E_UNKNOWN_READER:
			retval = "SCARD_E_UNKNOWN_READER";
			return("SCARD_E_UNKNOWN_READER");
			break;
		case SCARD_E_TIMEOUT:
			retval = "SCARD_E_TIMEOUT";
			return("SCARD_E_TIMEOUT");
			break;
		case SCARD_E_SHARING_VIOLATION:
			retval = "SCARD_E_SHARING_VIOLATION";
			return("SCARD_E_SHARING_VIOLATION");
			break;
		case SCARD_E_NO_SMARTCARD:
			retval = "SCARD_E_NO_SMARTCARD";
			return("SCARD_E_NO_SMARTCARD");
			break;
		case SCARD_E_UNKNOWN_CARD:
			retval = "SCARD_E_UNKNOWN_CARD";
			return("SCARD_E_UNKNOWN_CARD");
			break;
		case SCARD_E_PROTO_MISMATCH:
			retval = "SCARD_E_PROTO_MISMATCH";
			return("SCARD_E_PROTO_MISMATCH");
			break;
		case SCARD_E_NOT_READY:
			retval = "SCARD_E_NOT_READY";
			return("SCARD_E_NOT_READY");
			break;
		case SCARD_E_SYSTEM_CANCELLED:
			retval = "SCARD_E_SYSTEM_CANCELLED";
			return("SCARD_E_SYSTEM_CANCELLED");
			break;
		case SCARD_E_NOT_TRANSACTED:
			retval = "SCARD_E_NOT_TRANSACTED";
			return("SCARD_E_NOT_TRANSACTED");
			break;
		case SCARD_E_READER_UNAVAILABLE:
			retval = "SCARD_E_READER_UNAVAILABLE";
			return("SCARD_E_READER_UNAVAILABLE");
			break;
		case SCARD_W_UNSUPPORTED_CARD:
			retval = "SCARD_W_UNSUPPORTED_CARD";
			return("SCARD_W_UNSUPPORTED_CARD");
			break;
		case SCARD_W_UNRESPONSIVE_CARD:
			retval = "SCARD_W_UNRESPONSIVE_CARD";
			return("SCARD_W_UNRESPONSIVE_CARD");
			break;
		case SCARD_W_UNPOWERED_CARD:
			retval = "SCARD_W_UNPOWERED_CARD";
			return("SCARD_W_UNPOWERED_CARD");
			break;
		case SCARD_W_RESET_CARD:
			retval = "SCARD_W_RESET_CARD";
			return("SCARD_W_RESET_CARD");
			break;
		case SCARD_W_REMOVED_CARD:
			retval = "SCARD_W_REMOVED_CARD";
			return("SCARD_W_REMOVED_CARD");
			break;
		case SCARD_E_PCI_TOO_SMALL:
			retval = "SCARD_E_PCI_TOO_SMALL";
			return("SCARD_E_PCI_TOO_SMALL");
			break;
		case SCARD_E_READER_UNSUPPORTED:
			retval = "SCARD_E_READER_UNSUPPORTED";
			return("SCARD_E_READER_UNSUPPORTED");
			break;
		case SCARD_E_DUPLICATE_READER:
			retval = "SCARD_E_DUPLICATE_READER";
			return("SCARD_E_DUPLICATE_READER");
			break;
		case SCARD_E_CARD_UNSUPPORTED:
			retval = "SCARD_E_CARD_UNSUPPORTED";
			return("SCARD_E_CARD_UNSUPPORTED");
			break;
		case SCARD_E_NO_SERVICE:
			retval = "SCARD_E_NO_SERVICE";
			return("SCARD_E_NO_SERVICE");
			break;
		case SCARD_E_SERVICE_STOPPED:
			retval = "SCARD_E_SERVICE_STOPPED";
			return("SCARD_E_SERVICE_STOPPED");
			break;
		case SCARD_W_INSERTED_CARD:
			retval = "SCARD_W_INSERTED_CARD";
			return("SCARD_W_INSERTED_CARD");
			break;
		case SCARD_E_UNSUPPORTED_FEATURE:
			retval = "SCARD_E_UNSUPPORTED_FEATURE";
			return("SCARD_E_UNSUPPORTED_FEATURE");
			break;
	}

	if (retval == NULL) {
		retval = "UNKNOWN";
	return("UNKNOWN");
	}

static const char *CACKEY_DEBUG_FUNC_OBJID_TO_STR(uint16_t objid) {
	switch (objid) {
		case 0x2000:
			return("CACKEY_TLV_OBJID_GENERALINFO");
		case 0x2100:
			return("CACKEY_TLV_OBJID_PROPERSONALINFO");
		case 0x3000:
			return("CACKEY_TLV_OBJID_ACCESSCONTROL");
		case 0x4000:
			return("CACKEY_TLV_OBJID_LOGIN");
		case 0x5000:
			return("CACKEY_TLV_OBJID_CARDINFO");
		case 0x6000:
			return("CACKEY_TLV_OBJID_BIOMETRICS");
		case 0x7000:
			return("CACKEY_TLV_OBJID_DIGITALSIGCERT");
		case 0x0200:
			return("CACKEY_TLV_OBJID_CAC_PERSON");
		case 0x0202:
			return("CACKEY_TLV_OBJID_CAC_BENEFITS");
		case 0x0203:
			return("CACKEY_TLV_OBJID_CAC_OTHERBENEFITS");
		case 0x0201:
			return("CACKEY_TLV_OBJID_CAC_PERSONNEL");
		case 0x02FE:
			return("CACKEY_TLV_OBJID_CAC_PKICERT");
	}
	
	return(retval);
	return("UNKNOWN");
}

static const char *CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(uint8_t apptype) {
	switch (apptype) {
		case 0x01:
			return("CACKEY_TLV_APP_GENERIC");
		case 0x02:
			return("CACKEY_TLV_APP_SKI");
		case 0x03:
			return("CACKEY_TLV_APP_GENERIC | CACKEY_TLV_APP_SKI");
		case 0x04:
			return("CACKEY_TLV_APP_PKI");
		case 0x05:
			return("CACKEY_TLV_APP_GENERIC | CACKEY_TLV_APP_PKI");
		case 0x06:
			return("CACKEY_TLV_APP_SKI | CACKEY_TLV_APP_PKI");
		case 0x07:
			return("CACKEY_TLV_APP_GENERIC | CACKEY_TLV_APP_SKI | CACKEY_TLV_APP_PKI");
	}

	return("INVALID");
}

#  define malloc(x) CACKEY_DEBUG_FUNC_MALLOC(x, __func__)
#  define realloc(x, y) CACKEY_DEBUG_FUNC_REALLOC(x, y, __func__)
#else
#  define CACKEY_DEBUG_PRINTF(x...) /**/
#  define CACKEY_DEBUG_PRINTBUF(f, x, y) /**/
#  define CACKEY_DEBUG_PERROR(x) /**/
#  define CACKEY_DEBUG_FUNC_TAG_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_OBJID_TO_STR(x) "DEBUG_DISABLED"
#  define CACKEY_DEBUG_FUNC_APPTYPE_TO_STR(x) "DEBUG_DISABLED"
#endif

struct cackey_identity {
	CK_ATTRIBUTE *attributes;
	CK_ULONG attributes_count;
};

505
506
507
508
509
510
511





















512





513
514

515
516
517
518


519





520
521
522
523
524
525
526
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

503
504
505
506
507
508
509
510
511
512
513
514
515
516
517







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+


+



-
+
+

+
+
+
+
+








	char *pcsc_reader;

	int pcsc_card_connected;
	SCARDHANDLE pcsc_card;
};

typedef enum {
	CACKEY_TLV_APP_GENERIC = 0x01,
	CACKEY_TLV_APP_SKI     = 0x02,
	CACKEY_TLV_APP_PKI     = 0x04
} cackey_tlv_apptype;

typedef enum {
	CACKEY_TLV_OBJID_GENERALINFO       = 0x2000,
	CACKEY_TLV_OBJID_PROPERSONALINFO   = 0x2100,
	CACKEY_TLV_OBJID_ACCESSCONTROL     = 0x3000,
	CACKEY_TLV_OBJID_LOGIN             = 0x4000,
	CACKEY_TLV_OBJID_CARDINFO          = 0x5000,
	CACKEY_TLV_OBJID_BIOMETRICS        = 0x6000,
	CACKEY_TLV_OBJID_DIGITALSIGCERT    = 0x7000,
	CACKEY_TLV_OBJID_CAC_PERSON        = 0x0200,
	CACKEY_TLV_OBJID_CAC_BENEFITS      = 0x0202,
	CACKEY_TLV_OBJID_CAC_OTHERBENEFITS = 0x0203,
	CACKEY_TLV_OBJID_CAC_PERSONNEL     = 0x0201,
	CACKEY_TLV_OBJID_CAC_PKICERT       = 0x02FE
} cackey_tlv_objectid;

struct cackey_tlv_cardurl {
	unsigned char        rid[5];
	cackey_tlv_apptype   apptype;
	cackey_tlv_objectid  objectid;
	cackey_tlv_objectid  appid;
	unsigned char        pinid;
};

struct cackey_tlv_entity;
struct cackey_tlv_entity {
	uint8_t tag;
	size_t length;
	unsigned char *value_buf; /* Raw buffer */

	union {
	void *value;
		struct cackey_tlv_cardurl *value_cardurl;
		uint8_t value_byte;
	};

	struct cackey_tlv_entity *_next;
};

/* CACKEY Global Handles */
static void *cackey_biglock = NULL;
static struct cackey_session cackey_sessions[128];
static struct cackey_slot cackey_slots[128];
static int cackey_initialized = 0;
915
916
917
918
919
920
921
922
923



























924
925

926
927
928

929

930
931
932
933
934
935
936
937

938
939
940
941
942
943
944
945
946

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962

963
964
965
966
967
968

969
970
971
972
973
974
975

976
977
978
979
980
981
982

983
984
985
986
987
988

989
990
991
992
993

994
995
996
997

998
999
1000
1001
1002
1003
1004
1005




1006

1007

1008


1009
1010
1011
1012




















1013



1014
1015





1016
1017
1018
1019




1020



1021
1022


1023
1024
1025
1026

1027
1028
1029
1030

1031

1032
1033
1034
1035
1036
1037
1038
1039
1040























1041
1042
1043
1044
1045
1046
1047
906
907
908
909
910
911
912


913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946

947
948
949
950
951
952
953
954

955
956
957
958
959
960
961
962
963

964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979

980
981
982
983
984
985

986
987
988
989
990
991
992

993
994
995
996
997
998
999

1000
1001
1002
1003
1004
1005

1006
1007
1008
1009
1010

1011
1012
1013
1014

1015
1016
1017
1018
1019




1020
1021
1022
1023
1024
1025

1026
1027
1028
1029




1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053


1054
1055
1056
1057
1058

1059
1060
1061
1062
1063
1064
1065

1066
1067
1068
1069

1070
1071
1072
1073
1074

1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090

1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120







-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


+



+
-
+







-
+








-
+















-
+





-
+






-
+






-
+





-
+




-
+



-
+




-
-
-
-
+
+
+
+

+
-
+

+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
-
-
+
+
+
+
+
-



+
+
+
+
-
+
+
+

-
+
+



-
+




+

+








-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







	}

	CACKEY_DEBUG_PRINTF("Successfully selected file");

	return(0);
}

static int cackey_read_tlv(struct cackey_slot *slot, int follow_url) {
	struct cackey_tlv_entity curr_entity;
static void cackey_free_tlv(struct cackey_tlv_entity *root) {
	struct cackey_tlv_entity *curr, *next;

	for (curr = root; curr; curr = next) {
		next = curr->_next;

		switch (curr->tag) {
			case GSCIS_TAG_ACR_TABLE:
				if (curr->value) {
					free(curr->value);
				}
				break;
			case GSCIS_TAG_CARDURL:
				if (curr->value_cardurl) {
					free(curr->value_cardurl);
				}
				break;
		}

		free(curr);
	}

	return;
}

static struct cackey_tlv_entity *cackey_read_tlv(struct cackey_slot *slot) {
	struct cackey_tlv_entity *curr_entity, *root = NULL, *last = NULL;
	unsigned char tlen_buf[2], tval_buf[1024], *tval;
	unsigned char vlen_buf[2], vval_buf[8192], *vval;
	unsigned char *tmpbuf;
	ssize_t tlen, vlen;
	ssize_t read_ret;
	size_t offset_t = 0, offset_v = 0;
	unsigned char tag;
	int select_ret;
	size_t length;

	CACKEY_DEBUG_PRINTF("Called");

	read_ret = cackey_read_buffer(slot, tlen_buf, sizeof(tlen_buf), 1, offset_t);
	if (read_ret != sizeof(tlen_buf)) {
		CACKEY_DEBUG_PRINTF("Read failed, returning in failure");

		return(0);
		return(NULL);
	}

	tlen = (tlen_buf[1] << 8) | tlen_buf[0];

	read_ret = cackey_read_buffer(slot, vlen_buf, sizeof(vlen_buf), 2, offset_v);
	if (read_ret != sizeof(vlen_buf)) {
		CACKEY_DEBUG_PRINTF("Read failed, returning in failure");

		return(0);
		return(NULL);
	}

	vlen = (vlen_buf[1] << 8) | vlen_buf[0];

	CACKEY_DEBUG_PRINTF("Tag Length = %i, Value Length = %i", tlen, vlen);

	tlen -= 2;
	offset_t += 2;

	vlen -= 2;
	offset_v += 2;

	if (tlen > sizeof(tval_buf)) {
		CACKEY_DEBUG_PRINTF("Tag length is too large, returning in failure");

		return(0);
		return(NULL);
	}

	if (vlen > sizeof(vval_buf)) {
		CACKEY_DEBUG_PRINTF("Value length is too large, returning in failure");

		return(0);
		return(NULL);
	}

	read_ret = cackey_read_buffer(slot, tval_buf, tlen, 1, offset_t);
	if (read_ret != tlen) {
		CACKEY_DEBUG_PRINTF("Unable to read entire T-buffer, returning in failure");

		return(0);
		return(NULL);
	}

	read_ret = cackey_read_buffer(slot, vval_buf, vlen, 2, offset_v);
	if (read_ret != vlen) {
		CACKEY_DEBUG_PRINTF("Unable to read entire V-buffer, returning in failure");

		return(0);
		return(NULL);
	}

	tval = tval_buf;
	vval = vval_buf;
	while (tlen > 0 && vlen > 0) {
		curr_entity.tag = *tval;
		tag = *tval;
		tval++;
		tlen--;

		if (*tval == 0xff) {
			curr_entity.length = (tval[2] << 8) | tval[1];
			length = (tval[2] << 8) | tval[1];
			tval += 3;
			tlen -= 3;
		} else {
			curr_entity.length = *tval;
			length = *tval;
			tval++;
			tlen--;
		}

		CACKEY_DEBUG_PRINTF("Tag: %s (%02x)", CACKEY_DEBUG_FUNC_TAG_TO_STR(curr_entity.tag), (unsigned int) curr_entity.tag);
		CACKEY_DEBUG_PRINTBUF("Value:", vval, curr_entity.length);
		vval += curr_entity.length;
		vlen -= curr_entity.length;
		CACKEY_DEBUG_PRINTF("Tag: %s (%02x)", CACKEY_DEBUG_FUNC_TAG_TO_STR(tag), (unsigned int) tag);
		CACKEY_DEBUG_PRINTBUF("Value:", vval, length);
		vval += length;
		vlen -= length;

		curr_entity = NULL;
		switch (curr_entity.tag) {
		switch (tag) {
			case GSCIS_TAG_CARDURL:
				curr_entity = malloc(sizeof(*curr_entity));
				curr_entity->value_cardurl = malloc(sizeof(*curr_entity->value_cardurl));
				if (follow_url) {
					unsigned char aid[7];
					memcpy(aid, vval, 5);
					memcpy(aid + 5, vval + 8, 2);

				memcpy(curr_entity->value_cardurl->rid, vval, 5);
				curr_entity->value_cardurl->apptype = vval[5];
				curr_entity->value_cardurl->objectid = (vval[6] << 8) | vval[7];
				curr_entity->value_cardurl->appid = (vval[8] << 8) | vval[9];

				curr_entity->tag = tag;
				curr_entity->_next = NULL;

				break;
			case GSCIS_TAG_ACR_TABLE:
				curr_entity = malloc(sizeof(*curr_entity));
				tmpbuf = malloc(length);

				memcpy(tmpbuf, vval, length);

				curr_entity->tag = tag;
				curr_entity->length = length;
				curr_entity->value = tmpbuf;
				curr_entity->_next = NULL;

				break;
			case GSCIS_TAG_PKCS15:
				curr_entity = malloc(sizeof(*curr_entity));
					select_ret = cackey_select_applet(slot, aid, 7);
					if (select_ret < 0) {

				curr_entity->tag = tag;
				curr_entity->value_byte = vval[0];
				curr_entity->_next = NULL;

						CACKEY_DEBUG_PRINTF("Failed to select applet");
						break;
					}

		if (curr_entity != NULL) {
			if (root == NULL) {
				root = curr_entity;
			}
					cackey_read_tlv(slot, 0);

			if (last != NULL) {
				last->_next = curr_entity;
				}
				break;

			last = curr_entity;
		}
	}

	return(0);
	return(root);
}

/* Returns 1 if a token is in the specified slot, 0 otherwise */
static int cackey_token_present(struct cackey_slot *slot) {
	struct cackey_tlv_entity *tlvs, *curr;
	unsigned char ccc_aid[] = {0xa0, 0x00, 0x00, 0x01, 0x16, 0xdb, 0x00};
	unsigned char curr_aid[7];
	int send_ret;

	/* Select the CCC Applet */
	send_ret = cackey_select_applet(slot, ccc_aid, sizeof(ccc_aid));
	if (send_ret < 0) {
		return(0);
	}

	cackey_read_tlv(slot, 1);
	tlvs = cackey_read_tlv(slot);

	for (curr = tlvs; curr; curr = curr->_next) {
		CACKEY_DEBUG_PRINTF("Found tag: %s", CACKEY_DEBUG_FUNC_TAG_TO_STR(curr->tag));
		switch (curr->tag) {
			case GSCIS_TAG_CARDURL:
				if ((curr->value_cardurl->apptype & CACKEY_TLV_APP_PKI) == CACKEY_TLV_APP_PKI) {
					CACKEY_DEBUG_PRINTBUF("RID:", curr->value_cardurl->rid, sizeof(curr->value_cardurl->rid));
					CACKEY_DEBUG_PRINTF("AppID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(curr->value_cardurl->appid), (unsigned long) curr->value_cardurl->appid);
					CACKEY_DEBUG_PRINTF("ObjectID = %s/%04lx", CACKEY_DEBUG_FUNC_OBJID_TO_STR(curr->value_cardurl->objectid), (unsigned long) curr->value_cardurl->objectid);

					memcpy(curr_aid, curr->value_cardurl->rid, sizeof(curr->value_cardurl->rid));
					curr_aid[sizeof(curr_aid) - 2] = (curr->value_cardurl->appid >> 8) & 0xff;
					curr_aid[sizeof(curr_aid) - 1] = curr->value_cardurl->appid & 0xff;

					cackey_select_applet(slot, curr_aid, sizeof(curr_aid));
					cackey_select_file(slot, curr->value_cardurl->objectid);
				}
				break;
		}
	}

	cackey_free_tlv(tlvs);

	return(1);
}

/* Returns 0 on success */
static int cackey_mutex_create(void **mutex) {
	pthread_mutex_t *pthread_mutex;