Diff

Differences From Artifact [1be2f8a22e]:

To Artifact [0661f619de]:


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);
	}
3396
3397
3398
3399
3400
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
3445
3446
3447
3448
3449
3450
3451
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
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
3445
3446


3447
3448
3449
3450
3451
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
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519






3520



3521

3522



3523
3524



3525
3526
3527
3528
3529
3530
3531

3532
3533
3534
3535
3536
3537
3538
3539







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





-
-
+
+



+
+
-
-
+
+
+
+
+
+
+

+
-
+


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

-
+
-

-
+






+
+
-
+
+


















+
+
+
+
+
+



-
-
-
-
-
-
+
-
-
-

-
+
-
-
-
+

-
-
-







-
+








			cackey_free_certs(identities[id_idx].pcsc_identity, 1, 1);
		}
	}

	free(identities);
}

static unsigned long cackey_read_dod_identities(struct cackey_identity *identities, unsigned long id_idx, unsigned long num_dod_certs) {
	unsigned long cert_idx;

	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++;
	}

	return(id_idx);
}

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;
	int include_extra_certs = 1;
	unsigned long num_certs, num_dod_certs, cert_idx;
	int include_extra_certs = 0;

	CACKEY_DEBUG_PRINTF("Called.");

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

		return(NULL);
	}

#ifdef CACKEY_CARD_SLOT_INCLUDE_EXTRA_CERTS
	include_extra_certs = 1;
#endif

	if (getenv("CACKEY_DOD_CERTS_ON_HW_SLOTS") != NULL) {
		include_extra_certs = 0;
		include_extra_certs = 1;
	}

	if (getenv("CACKEY_NO_DOD_CERTS_ON_HW_SLOTS") != NULL) {
	if (include_extra_certs) {
		num_extra_certs = sizeof(extra_certs) / sizeof(extra_certs[0]);

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

	if (getenv("CACKEY_NO_EXTRA_CERTS") != NULL) {
		num_dod_certs = 0;
	} else {
		num_dod_certs = sizeof(extra_certs) / sizeof(extra_certs[0]);
	}

	if (slot->internal) {
		num_ids = num_dod_certs;

		if (num_ids != 0) {
			identities = malloc(num_ids * sizeof(*identities));

			cackey_read_dod_identities(identities, 0, num_dod_certs);
		} else {
			identities = NULL;
		}

	if (ids_found == NULL) {
		*ids_found = num_ids;
		CACKEY_DEBUG_PRINTF("Error.  ids_found is NULL");

		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;

		if (include_extra_certs) {
		num_ids += num_extra_certs * 3;
			num_ids += num_dod_certs;
		}

		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++) {
				identities[id_idx].attributes = cackey_get_attributes(curr_id_type, &pcsc_identities[cert_idx], cert_idx, &identities[id_idx].attributes_count);

				identities[id_idx].pcsc_identity = malloc(sizeof(*identities[id_idx].pcsc_identity));
				memcpy(identities[id_idx].pcsc_identity, &pcsc_identities[cert_idx], sizeof(*identities[id_idx].pcsc_identity));

				identities[id_idx].pcsc_identity->certificate = malloc(pcsc_identities[cert_idx].certificate_len);
				memcpy(identities[id_idx].pcsc_identity->certificate, pcsc_identities[cert_idx].certificate, pcsc_identities[cert_idx].certificate_len);

				id_idx++;
			}
		}

		if (include_extra_certs) {
			CACKEY_DEBUG_PRINTF("Including DoD Certificates on hardware slot");

			cackey_read_dod_identities(identities, id_idx, num_dod_certs);
		}

		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;
		return(identities);
			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
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595







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







		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
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646







+
+
+
+







			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
3690
3691
3692
3693
3694
3695
3696

3697
3698
3699
3700
3701
3702
3703
3704







-
+








/*
 * 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
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742







+
+
+
+







	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
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799







+

+
+
+
+
+
+
+







			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
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832

3833



3834
3835
3836


3837
3838
3839
3840
3841
3842
3843
3844
3845







+









+
+
+






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







					}

					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
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876




3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908







+
+



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







		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
3946
3947
3948
3949
3950
3951
3952

3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964







-
+
+
+
+
+







		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) {