Changes On Branch 90faf75892ba3296

Changes In Branch dodcerts-on-seperate-slot Through [90faf75892] Excluding Merge-Ins

This is equivalent to a diff from 07d8b72d7d to 90faf75892

2012-07-24
20:53
Removed win32 SDK files, which are now part of mingw32 (untested) check-in: c1fa623247 user: rkeene tags: trunk
2012-07-22
15:55
Create new branch named "require-login-if-needed" check-in: 459f215faf user: rkeene tags: require-login-if-needed
2012-07-21
06:50
Updated to allow the user to specify (via environment variables) whether or not to include the DoD certificates on the hardware slot tokens check-in: b957a3fa2e user: rkeene tags: dodcerts-on-seperate-slot
06:19
Protected access to cackey_slots with mutex check-in: 90faf75892 user: rkeene tags: dodcerts-on-seperate-slot
06:09
Added support for treating the DoD certs as a seperate slot check-in: b6b2190360 user: rkeene tags: dodcerts-on-seperate-slot
04:55
Create new branch named "dodcerts-on-seperate-slot" check-in: caac1986d6 user: rkeene tags: dodcerts-on-seperate-slot
2012-07-20
01:05
Corrected arithmetic on a void pointer check-in: 07d8b72d7d user: rkeene tags: trunk
01:04
Corrected casting to for %p formatting check-in: c634e02a7f user: rkeene tags: trunk

Modified cackey.c from [1be2f8a22e] to [8e07ff4bd1].

709
710
711
712
713
714
715

716
717
718
719
720
721
722
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723







+







	CK_VOID_PTR decrypt_mech_parm;
	CK_ULONG decrypt_mech_parmlen;
	struct cackey_identity *decrypt_identity;
};

struct cackey_slot {
	int active;
	int internal;

	char *pcsc_reader;

	int pcsc_card_connected;
	SCARDHANDLE pcsc_card;

	int transaction_depth;
853
854
855
856
857
858
859





860
861
862
863
864
865
866
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872







+
+
+
+
+







 */
static void cackey_slots_disconnect_all(void) {
	uint32_t idx;

	CACKEY_DEBUG_PRINTF("Called.");

	for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) {
		if (cackey_slots[idx].internal) {
			/* Skip internal slots */
			continue;
		}

		if (cackey_slots[idx].pcsc_card_connected) {
			CACKEY_DEBUG_PRINTF("SCardDisconnect(%lu) called", (unsigned long) idx);

			SCardDisconnect(cackey_slots[idx].pcsc_card, SCARD_LEAVE_CARD);
		}

		if (cackey_slots[idx].label) {
2602
2603
2604
2605
2606
2607
2608






2609
2610
2611
2612
2613
2614
2615
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627







+
+
+
+
+
+







static cackey_ret cackey_token_present(struct cackey_slot *slot) {
	cackey_ret pcsc_connect_ret;
	DWORD reader_len, state, protocol, atr_len;
	BYTE atr[MAX_ATR_SIZE];
	LONG status_ret, scard_reconn_ret;

	CACKEY_DEBUG_PRINTF("Called.");

	if (slot->internal) {
		CACKEY_DEBUG_PRINTF("Returning token present (internal token)");

		return(CACKEY_PCSC_S_TOKENPRESENT);
	}

	pcsc_connect_ret = cackey_connect_card(slot);
	if (pcsc_connect_ret != CACKEY_PCSC_S_OK) {
		CACKEY_DEBUG_PRINTF("Unable to connect to card, returning token absent");

		return(CACKEY_PCSC_E_TOKENABSENT);
	}
3401
3402
3403
3404
3405
3406
3407
3408

3409
3410
3411
3412
3413
3414


3415
3416

3417
3418
3419
3420



3421

3422
3423
3424
3425












3426




3427
3428


3429
3430

3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3413
3414
3415
3416
3417
3418
3419

3420

3421
3422
3423


3424
3425
3426

3427
3428
3429


3430
3431
3432
3433
3434




3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451


3452
3453
3454

3455
3456
3457
3458
3459
3460
3461

3462
3463
3464
3465
3466
3467
3468







-
+
-



-
-
+
+

-
+


-
-
+
+
+

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

+
+
+
+
-
-
+
+

-
+






-







	free(identities);
}

static struct cackey_identity *cackey_read_identities(struct cackey_slot *slot, unsigned long *ids_found) {
	struct cackey_pcsc_identity *pcsc_identities;
	struct cackey_identity *identities;
	unsigned long num_ids, id_idx, curr_id_type;
	unsigned long num_certs, num_extra_certs, cert_idx;
	unsigned long num_certs, num_dod_certs, cert_idx;
	int include_extra_certs = 1;

	CACKEY_DEBUG_PRINTF("Called.");

	if (getenv("CACKEY_NO_EXTRA_CERTS") != NULL) {
		CACKEY_DEBUG_PRINTF("Asked not to include extra (DoD) certificates");
	if (ids_found == NULL) {
		CACKEY_DEBUG_PRINTF("Error.  ids_found is NULL");

		include_extra_certs = 0;
		return(NULL);
	}

	if (include_extra_certs) {
		num_extra_certs = sizeof(extra_certs) / sizeof(extra_certs[0]);
	if (slot->internal) {
		/* Add DoD Certificates and Netscape Trust Objects */
		num_dod_certs = sizeof(extra_certs) / sizeof(extra_certs[0]);

		num_ids = num_dod_certs * 3;
		CACKEY_DEBUG_PRINTF("Including %li DoD Certificates as objects on this token", num_extra_certs);
	} else {
		num_extra_certs = 0;
	}

		identities = malloc(num_ids * sizeof(*identities));

		id_idx = 0;
		for (cert_idx = 0; cert_idx < num_dod_certs; cert_idx++) {
			identities[id_idx].pcsc_identity = NULL;
			identities[id_idx].attributes = cackey_get_attributes(CKO_CERTIFICATE, &extra_certs[cert_idx], 0xf000 | cert_idx, &identities[id_idx].attributes_count);
			id_idx++;

			identities[id_idx].pcsc_identity = NULL;
			identities[id_idx].attributes = cackey_get_attributes(CKO_PUBLIC_KEY, &extra_certs[cert_idx], 0xf000 | cert_idx, &identities[id_idx].attributes_count);
			id_idx++;

			identities[id_idx].pcsc_identity = NULL;
			identities[id_idx].attributes = cackey_get_attributes(CKO_NETSCAPE_TRUST, &extra_certs[cert_idx], 0xf000 | cert_idx, &identities[id_idx].attributes_count);
			id_idx++;
		}
	if (ids_found == NULL) {
		CACKEY_DEBUG_PRINTF("Error.  ids_found is NULL");

		*ids_found = num_ids;

		return(NULL);
		return(identities);
	}

	pcsc_identities = cackey_read_certs(slot, NULL, &num_certs);
	if (pcsc_identities != NULL) {
		/* Convert number of Certs to number of objects */
		num_ids = (CKO_PRIVATE_KEY - CKO_CERTIFICATE + 1) * num_certs;
		num_ids += num_extra_certs * 3;

		identities = malloc(num_ids * sizeof(*identities));

		/* Add certificates, public keys, and private keys from the smartcard */
		id_idx = 0;
		for (cert_idx = 0; cert_idx < num_certs; cert_idx++) {
			for (curr_id_type = CKO_CERTIFICATE; curr_id_type <= CKO_PRIVATE_KEY; curr_id_type++) {
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464

3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484

3485
3486
3487
3488
3489
3490
3491
3476
3477
3478
3479
3480
3481
3482






3483



3484






3485
3486
3487
3488
3489
3490
3491
3492
3493

3494
3495
3496
3497
3498
3499
3500
3501







-
-
-
-
-
-
+
-
-
-

-
-
-
-
-
-









-
+








				id_idx++;
			}
		}

		cackey_free_certs(pcsc_identities, num_certs, 1);

		/* Add DoD Certificates and Netscape Trust Objects */
		for (cert_idx = 0; cert_idx < num_extra_certs; cert_idx++) {
			identities[id_idx].pcsc_identity = NULL;
			identities[id_idx].attributes = cackey_get_attributes(CKO_CERTIFICATE, &extra_certs[cert_idx], 0xf000 | cert_idx, &identities[id_idx].attributes_count);
			id_idx++;

		*ids_found = num_ids;
			identities[id_idx].pcsc_identity = NULL;
			identities[id_idx].attributes = cackey_get_attributes(CKO_PUBLIC_KEY, &extra_certs[cert_idx], 0xf000 | cert_idx, &identities[id_idx].attributes_count);
			id_idx++;

			identities[id_idx].pcsc_identity = NULL;
			identities[id_idx].attributes = cackey_get_attributes(CKO_NETSCAPE_TRUST, &extra_certs[cert_idx], 0xf000 | cert_idx, &identities[id_idx].attributes_count);
			id_idx++;
		}

		*ids_found = num_ids;
		return(identities);
	}

	*ids_found = 0;
	return(NULL);
}

CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) {
	CK_C_INITIALIZE_ARGS CK_PTR args;
	uint32_t idx;
	uint32_t idx, highest_slot;
	int mutex_init_ret;

	CACKEY_DEBUG_PRINTF("Called.");

	if (cackey_initialized) {
		CACKEY_DEBUG_PRINTF("Error.  Already initialized.");

3519
3520
3521
3522
3523
3524
3525















3526
3527
3528
3529
3530
3531
3532
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557







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







		cackey_slots[idx].active = 0;
		cackey_slots[idx].pcsc_reader = NULL;
		cackey_slots[idx].transaction_depth = 0;
		cackey_slots[idx].transaction_need_hw_lock = 0;
		cackey_slots[idx].slot_reset = 0;
		cackey_slots[idx].token_flags = 0;
		cackey_slots[idx].label = NULL;
		cackey_slots[idx].internal = 0;
	}

	if (getenv("CACKEY_NO_EXTRA_CERTS") != NULL) {
		CACKEY_DEBUG_PRINTF("Asked not to include DoD certificates");
	} else {
		highest_slot = (sizeof(cackey_slots) / sizeof(cackey_slots[0])) - 1;

		CACKEY_DEBUG_PRINTF("Including DoD certs in slot %lu", (unsigned long) highest_slot);

		cackey_slots[highest_slot].active = 1;
		cackey_slots[highest_slot].internal = 1;
		cackey_slots[highest_slot].label = (unsigned char *) "DoD Certificates";
		cackey_slots[highest_slot].pcsc_reader = "CACKey";
		cackey_slots[highest_slot].token_flags = 0;
	}

	cackey_initialized = 1;

	if (!cackey_biglock_init) {
		mutex_init_ret = cackey_mutex_create(&cackey_biglock);

3566
3567
3568
3569
3570
3571
3572




3573
3574
3575
3576
3577
3578
3579
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608







+
+
+
+







			C_CloseSession(idx);
		}
	}

	cackey_slots_disconnect_all();

	for (idx = 0; idx < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); idx++) {
		if (cackey_slots[idx].internal) {
			continue;
		}

		if (cackey_slots[idx].pcsc_reader) {
			free(cackey_slots[idx].pcsc_reader);
		}
	}

	cackey_pcsc_disconnect();

3623
3624
3625
3626
3627
3628
3629
3630

3631
3632
3633
3634
3635
3636
3637
3652
3653
3654
3655
3656
3657
3658

3659
3660
3661
3662
3663
3664
3665
3666







-
+








/*
 * Process list of readers, and create mapping between reader name and slot ID
 */
CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) {
	int mutex_retval;
	int pcsc_connect_ret;
	CK_ULONG count, slot_count = 0, currslot;
	CK_ULONG count, slot_count = 0, currslot, slot_idx;
	char *pcsc_readers, *pcsc_readers_s, *pcsc_readers_e;
	DWORD pcsc_readers_len;
	LONG scard_listreaders_ret;
	size_t curr_reader_len;

	CACKEY_DEBUG_PRINTF("Called.");

3658
3659
3660
3661
3662
3663
3664




3665
3666
3667
3668
3669
3670
3671
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704







+
+
+
+







	if (pSlotList) {
		CACKEY_DEBUG_PRINTF("Purging all slot information.");

		/* Only update the list of slots if we are actually being supply the slot information */
		cackey_slots_disconnect_all();

		for (currslot = 0; currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); currslot++) {
			if (cackey_slots[currslot].internal) {
				continue;
			}

			if (cackey_slots[currslot].pcsc_reader) {
				free(cackey_slots[currslot].pcsc_reader);

				cackey_slots[currslot].pcsc_reader = NULL;
			}

			if (cackey_slots[currslot].label) {
3706
3707
3708
3709
3710
3711
3712

3713







3714
3715
3716
3717
3718
3719
3720
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761







+

+
+
+
+
+
+
+







			scard_listreaders_ret = SCardListReaders(*cackey_pcsc_handle, NULL, pcsc_readers, &pcsc_readers_len);
			if (scard_listreaders_ret == SCARD_S_SUCCESS) {
				pcsc_readers_e = pcsc_readers + pcsc_readers_len;

				/* Start with Slot ID 1, to avoid a bug in GDM on RHEL */
				/* Bug 594911: https://bugzilla.redhat.com/show_bug.cgi?id=594911 */
				currslot = 1;
				slot_count = 0;
				while (pcsc_readers < pcsc_readers_e) {
					/* Find next available slot */
					for (; currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); currslot++) {
						if (!cackey_slots[currslot].active) {
							break;
						}
					}

					curr_reader_len = strlen(pcsc_readers);

					if ((pcsc_readers + curr_reader_len) > pcsc_readers_e) {
						break;
					}

					if (curr_reader_len == 0) {
3728
3729
3730
3731
3732
3733
3734

3735
3736
3737
3738
3739
3740
3741
3742
3743



3744
3745
3746
3747
3748
3749
3750

3751
3752
3753



3754
3755


3756
3757
3758
3759
3760
3761
3762
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794

3795



3796
3797
3798


3799
3800
3801
3802
3803
3804
3805
3806
3807







+









+
+
+






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







					}

					CACKEY_DEBUG_PRINTF("Found reader: %s", pcsc_readers);

					/* Only update the list of slots if we are actually being asked supply the slot information */
					if (pSlotList) {
						cackey_slots[currslot].active = 1;
						cackey_slots[currslot].internal = 0;
						cackey_slots[currslot].pcsc_reader = strdup(pcsc_readers);
						cackey_slots[currslot].pcsc_card_connected = 0;
						cackey_slots[currslot].transaction_depth = 0;
						cackey_slots[currslot].transaction_need_hw_lock = 0;
						cackey_slots[currslot].slot_reset = 1;
						cackey_slots[currslot].token_flags = CKF_LOGIN_REQUIRED;
						cackey_slots[currslot].label = NULL;

						cackey_mark_slot_reset(&cackey_slots[currslot]);
					} else {
						/* Artificially increase the number of active slots by what will become active */
						slot_count++;
					}
					currslot++;

					pcsc_readers += curr_reader_len + 1;
				}

				/* Start with Slot ID 1, to avoid a bug in GDM on RHEL */
				for (currslot = 0; currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0])); currslot++) {
				/* Bug 594911: https://bugzilla.redhat.com/show_bug.cgi?id=594911 */
				if (currslot > 1) {
					/* Start with Slot ID 1, to avoid a bug in GDM on RHEL */
					if (cackey_slots[currslot].active) {
						CACKEY_DEBUG_PRINTF("Found active slot %lu", (unsigned long) currslot);

					/* Bug 594911: https://bugzilla.redhat.com/show_bug.cgi?id=594911 */
					slot_count = currslot - 1;
						slot_count++;
					}
				}
			} else {
				CACKEY_DEBUG_PRINTF("Second call to SCardListReaders failed, return %s/%li", CACKEY_DEBUG_FUNC_SCARDERR_TO_STR(scard_listreaders_ret), (long) scard_listreaders_ret);
			}

			free(pcsc_readers_s);
		} else {
3779
3780
3781
3782
3783
3784
3785


3786
3787
3788



3789
3790
3791
3792

























3793
3794
3795
3796
3797
3798
3799
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838




3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870







+
+



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







		return(CKR_OK);
	}

	count = *pulCount;
	if (count < slot_count) {
		CACKEY_DEBUG_PRINTF("Error. User allocated %lu entries, but we have %lu entries.", count, slot_count);

		CACKEY_DEBUG_PRINTF("Returning CKR_BUFFER_TOO_SMALL");

		return(CKR_BUFFER_TOO_SMALL);	
	}

	mutex_retval = cackey_mutex_lock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Locking failed.");
	for (currslot = 0; currslot < slot_count; currslot++) {
		/* Start with Slot ID 1, to avoid a bug in GDM on RHEL */
		/* Bug 594911: https://bugzilla.redhat.com/show_bug.cgi?id=594911 */
		pSlotList[currslot] = currslot + 1;

		return(CKR_GENERAL_ERROR);
	}

	slot_idx = 0;
	for (currslot = 0; (currslot < (sizeof(cackey_slots) / sizeof(cackey_slots[0]))); currslot++) {
		if (!cackey_slots[currslot].active) {
			continue;
		}

		if (slot_idx >= count) {
			CACKEY_DEBUG_PRINTF("Error. User allocated %lu entries, but we just tried to write to the %lu index -- ignoring", count, slot_idx);

			continue;
		}

		pSlotList[slot_idx] = currslot;
		slot_idx++;
	}

	mutex_retval = cackey_mutex_unlock(cackey_biglock);
	if (mutex_retval != 0) {
		CACKEY_DEBUG_PRINTF("Error.  Unlocking failed.");

		return(CKR_GENERAL_ERROR);
	}

	*pulCount = slot_count;

	CACKEY_DEBUG_PRINTF("Returning CKR_OK (%i).  Found %lu readers.", CKR_OK, (unsigned long) slot_count);

	return(CKR_OK);
3837
3838
3839
3840
3841
3842
3843
3844





3845
3846
3847
3848
3849
3850
3851
3908
3909
3910
3911
3912
3913
3914

3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926







-
+
+
+
+
+







		CACKEY_DEBUG_PRINTF("Error. Invalid slot requested (%lu), slot not currently active", slotID);

		cackey_mutex_unlock(cackey_biglock);

		return(CKR_SLOT_ID_INVALID);
	}

	pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT;
	pInfo->flags = CKF_HW_SLOT;

	if (!cackey_slots[slotID].internal) {
		pInfo->flags |= CKF_REMOVABLE_DEVICE;
	}

	if (cackey_token_present(&cackey_slots[slotID]) == CACKEY_PCSC_S_TOKENPRESENT) {
		pInfo->flags |= CKF_TOKEN_PRESENT;
	}

	bytes_to_copy = strlen(cackey_slots[slotID].pcsc_reader);
	if (sizeof(pInfo->manufacturerID) < bytes_to_copy) {

Modified test.c from [7438606333] to [86bd0fe2e2].

234
235
236
237
238
239
240

241
242
243
244
245
246
247
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248







+







		printf("  Slot %lu:\n", currSlot);

		chk_rv = C_GetSlotInfo(slots[currSlot], &slotInfo);
		if (chk_rv != CKR_OK) {
			return(1);
		}

		printf("    Id     : %lu\n", (unsigned long) slots[currSlot]);
		printf("    Desc   : %.*s\n", 32, slotInfo.slotDescription);
		printf("    ManufID: %.*s\n", 32, slotInfo.manufacturerID);
		printf("    HWVers : %i.%i\n", slotInfo.hardwareVersion.major, slotInfo.hardwareVersion.minor);
		printf("    FWVers : %i.%i\n", slotInfo.firmwareVersion.major, slotInfo.firmwareVersion.minor);
		printf("    Flags  : ");
		if ((slotInfo.flags & CKF_TOKEN_PRESENT) == CKF_TOKEN_PRESENT) {
			printf("CKF_TOKEN_PRESENT ");
325
326
327
328
329
330
331





332
333
334
335
336
337
338
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344







+
+
+
+
+







			}
			printf("\n");
		}
	}

	chk_rv = C_OpenSession(slots[0], CKF_SERIAL_SESSION, NULL, NULL, &hSession);
	if (chk_rv == CKR_OK) {
		chk_rv = C_GetTokenInfo(slots[0], &tokenInfo);
		if (chk_rv != CKR_OK) {
			return(1);
		}

		if ((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED) {
			fgets_ret = NULL;

			while (fgets_ret == NULL) {
				printf("** ENTER PIN: ");
				fflush(stdout);