Christian Rank | 31 Jan 11:48
Picon
Favicon

C_FindObjectsInit does not always find certificate on token when called from Java application

Hello,

when dealing with accessing tokens from a Java application via OpenSC, I
noticed that the Sun/ORACLE PKCS11-Java implementation is not always
able to retrieve the certificate chain (stored on the token) for a key.

The objects on my token (Feitian PKI card) are:
> Private RSA Key [Private Key]
> 	Object Flags   : [0x3], private, modifiable
> 	Usage          : [0x12E], decrypt, sign, signRecover, unwrap, derive
> 	Access Flags   : [0x0]
> 	ModLength      : 2048
> 	Key ref        : 1 (0x1)
> 	Native         : yes
> 	Path           : 3f005015
> 	Auth ID        : 01
> 	ID             : 692b93bfd7d6f6dd86832f81d1b44adbe266f74d
> 	GUID           : {692b93bf-d7d6-f6dd-8683-2f81d1b44adb}
> 
> X.509 Certificate [/C=DE/L=Entenhausen/O=Dagobert Duck
Enterprises/OU=Geldspeicher/CN=Dagobert Duck]
> 	Object Flags   : [0x2], modifiable
> 	Authority      : no
> 	Path           : 3f0050153100
> 	ID             : 692b93bfd7d6f6dd86832f81d1b44adbe266f74d
> 	GUID           : {692b93bf-d7d6-f6dd-8683-2f81d1b44adb}
> 	Encoded serial : 02 01 03
> 
> X.509 Certificate [/C=DE/O=Deutsche Zertifizierungsstelle/OU=PKI der Deutschen
Zertifizierungsstelle/CN=Deutsche Zertifizierungsstelle Root CA]
> 	Object Flags   : [0x2], modifiable
> 	Authority      : yes
> 	Path           : 3f0050153101
> 	ID             : aff0e45b54ec084fdb987e76b655100963ca0be1
> 	GUID           : {aff0e45b-54ec-084f-db98-7e76b6551009}
> 	Encoded serial : 02 01 01

The certificate chain is:
>   0: /C=DE/L=Entenhausen/O=Dagobert Duck Enterprises/OU=Geldspeicher/CN=Dagobert Duck
>   1: /C=DE/O=Deutsche Zertifizierungsstelle/OU=PKI der Deutschen
Zertifizierungsstelle/CN=Deutsche Zertifizierungsstelle Root CA

Accessing the keystore on this token with the Java keytool utility yields:
> Keystore type: PKCS11
> Keystore provider: SunPKCS11-OpenSC
> 
> Your keystore contains 2 entries
> 
> Alias name: /C=DE/L=Entenhausen/O=Dagobert Duck Enterprises/OU=Geldspeicher/CN=Dagobert Duck
> Entry type: PrivateKeyEntry
> Certificate chain length: 1
> Certificate[1]:
> Owner: CN=Dagobert Duck, OU=Geldspeicher, O=Dagobert Duck Enterprises, L=Entenhausen, C=DE
> Issuer: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Serial number: 3
> Valid from: Tue Jan 31 08:18:17 CET 2012 until: Tue Jan 31 08:18:17 CET 2017
> 
> Alias name: /C=DE/O=Deutsche Zertifizierungsstelle/OU=PKI der Deutschen
Zertifizierungsstelle/CN=Deutsche Zertifizierungsstelle Root CA
> Entry type: trustedCertEntry
> 
> Owner: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Issuer: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Serial number: 1
> Valid from: Mon Jan 30 11:03:09 CET 2012 until: Fri Jan 30 11:03:09 CET 2032

Note the length of certificate chain (1), since the root certificate is
not included in the chain (but should be).

I tracked down this problem to the function C_FindObjectsInit which
should find a certificate with a given subject but does not always succeed.

Finally I ended in framework-pkcs15.c where in function
pkcs15_cert_cmp_attribute the search condition for CKA_ISSUER is dealt
with specially. I expanded this code slightly to do also the same
special check for CKA_SUBJECT.

The patched code solves this problem: Now in Java the certificate chain
gets identified correctly. Output of Java keytool utility:

> Keystore type: PKCS11
> Keystore provider: SunPKCS11-OpenSC
> 
> Your keystore contains 2 entries
> 
> Alias name: /C=DE/L=Entenhausen/O=Dagobert Duck Enterprises/OU=Geldspeicher/CN=Dagobert Duck
> Entry type: PrivateKeyEntry
> Certificate chain length: 2
> Certificate[1]:
> Owner: CN=Dagobert Duck, OU=Geldspeicher, O=Dagobert Duck Enterprises, L=Entenhausen, C=DE
> Issuer: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Serial number: 3
> Valid from: Tue Jan 31 08:18:17 CET 2012 until: Tue Jan 31 08:18:17 CET 2017
> Certificate[2]:
> Owner: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Issuer: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Serial number: 1
> Valid from: Mon Jan 30 11:03:09 CET 2012 until: Fri Jan 30 11:03:09 CET 2032
> 
> Alias name: /C=DE/O=Deutsche Zertifizierungsstelle/OU=PKI der Deutschen
Zertifizierungsstelle/CN=Deutsche Zertifizierungsstelle Root CA
> Entry type: trustedCertEntry
> 
> Owner: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Issuer: CN=Deutsche Zertifizierungsstelle Root CA, OU=PKI der Deutschen Zertifizierungsstelle,
O=Deutsche Zertifizierungsstelle, C=DE
> Serial number: 1
> Valid from: Mon Jan 30 11:03:09 CET 2012 until: Fri Jan 30 11:03:09 CET 2032

Patch file is attached (works with current git version but also version
0.12.2 and 0.12.1). I would be glad if this could be included in the
next OpenSC release.

Best regards,
	Christian

-- 
Dr. Christian Rank
Rechenzentrum Universität Passau
Bereich Netzwerk und Telekommunikation
Innstr. 33
D-94032 Passau
GERMANY
Tel.: 0851/509-1838
Fax:  0851/509-1802
PGP public key see http://www.rz.uni-passau.de/mitarbeiter/rank
*** framework-pkcs15.c.orig	2012-01-31 11:13:39.000000000 +0100
--- framework-pkcs15.c	2012-01-31 11:14:48.000000000 +0100
***************
*** 2418,2423 ****
--- 2418,2446 ----
  		 && !memcmp(cert->cert_data->issuer, data, len))
  			return 1;
  		break;
+         case CKA_SUBJECT:
+ 		if (check_cert_data_read(fw_data, cert) != 0)
+ 			break;
+ 		if (cert->cert_data->subject_len == 0)
+ 			break;
+ 		data = (u8 *) attr->pValue;
+ 		len = attr->ulValueLen;
+ 		/* SEQUENCE is tag 0x30, SET is 0x31
+ 		 * I know this code is icky, but hey... this is netscape
+ 		 * we're dealing with :-) */
+ 		if (cert->cert_data->subject[0] == 0x31
+ 		 && data[0] == 0x30 && len >= 2) {
+ 			/* skip the length byte(s) */
+ 			len = (data[1] & 0x80)? (data[1] & 0x7F) : 0;
+ 			if (attr->ulValueLen < len + 2)
+ 				break;
+ 			data += len + 2;
+ 			len = attr->ulValueLen - len - 2;
+ 		}
+ 		if (len == cert->cert_data->subject_len
+ 		 && !memcmp(cert->cert_data->subject, data, len))
+ 			return 1;
+ 		break;
  	default:
  		return sc_pkcs11_any_cmp_attribute(session, object, attr);
  	}

Gmane