[pkg-opensc-commit] [opensc] 30/295: pkcs11-tool: various improvements, extensions, fixes, cleanup

Eric Dorland eric at moszumanska.debian.org
Sat Jun 24 21:11:13 UTC 2017


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository opensc.

commit 4441efa6daf4b06dd97e0435b9830ab942c24558
Author: David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Jun 29 14:18:56 2016 +0200

    pkcs11-tool: various improvements, extensions, fixes, cleanup
    
    ========================================
    rebased by VTA -- commits are forged to one,
    excluding the following chunk
    (reason -- if not explicitely indicated, the mechanism has to be found out using the mechanism flags):
    
    @@ -1713,8 +1713,9 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
                            int ii;
    
                            if (!opt_mechanism_used)
    +                               opt_mechanism = CKM_EC_KEY_PAIR_GEN;
                                    if (!find_mechanism(slot, CKF_GENERATE_KEY_PAIR, mtypes, mtypes_num, &opt_mechanism))
    -                                       util_fatal("Generate EC key mechanism not supported\n");
    +                                       util_warn("Generate EC key mechanism not listed as supported");
    
                            for (ii=0; ec_curve_infos[ii].name; ii++)   {
                                    if (!strcmp(ec_curve_infos[ii].name, type + 3))
    
    will close PR #747
---
 src/pkcs11/pkcs11.h     |   4 +
 src/tools/pkcs11-tool.c | 593 +++++++++++++++++++++++++++++++++---------------
 2 files changed, 419 insertions(+), 178 deletions(-)

diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h
index 9967025..74b13c6 100644
--- a/src/pkcs11/pkcs11.h
+++ b/src/pkcs11/pkcs11.h
@@ -657,6 +657,10 @@ typedef unsigned long ck_mechanism_type_t;
 #define CKM_EC_KEY_PAIR_GEN		(0x1040UL)
 #define CKM_ECDSA			(0x1041UL)
 #define CKM_ECDSA_SHA1			(0x1042UL)
+#define CKM_ECDSA_SHA224		(0x1043UL)
+#define CKM_ECDSA_SHA256		(0x1044UL)
+#define CKM_ECDSA_SHA384		(0x1045UL)
+#define CKM_ECDSA_SHA512		(0x1046UL)
 #define CKM_ECDH1_DERIVE		(0x1050UL)
 #define CKM_ECDH1_COFACTOR_DERIVE	(0x1051UL)
 #define CKM_ECMQV_DERIVE		(0x1052UL)
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index 1c32b74..cb2244e 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -393,7 +393,7 @@ static int		p11_test(CK_SESSION_HANDLE session);
 static int test_card_detection(int);
 static int		hex_to_bin(const char *in, CK_BYTE *out, size_t *outlen);
 static void		pseudo_randomize(unsigned char *data, size_t dataLen);
-static void		test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
+static CK_SESSION_HANDLE test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
 static void		test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
 #ifndef _WIN32
 static void		test_fork(void);
@@ -521,7 +521,7 @@ int main(int argc, char * argv[])
 			do_set_id = 1;
 			new_object_id_len = sizeof(new_object_id);
 			if (!hex_to_bin(optarg, new_object_id, &new_object_id_len)) {
-				printf("Invalid ID \"%s\"\n", optarg);
+				fprintf(stderr, "Invalid ID \"%s\"\n", optarg);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
 			action_count++;
@@ -540,14 +540,14 @@ int main(int argc, char * argv[])
 			else if (strcmp(optarg, "data") == 0)
 				opt_object_class = CKO_DATA;
 			else {
-				printf("Unsupported object type \"%s\"\n", optarg);
+				fprintf(stderr, "Unsupported object type \"%s\"\n", optarg);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
 			break;
 		case 'd':
 			opt_object_id_len = sizeof(opt_object_id);
 			if (!hex_to_bin(optarg, opt_object_id, &opt_object_id_len)) {
-				printf("Invalid ID \"%s\"\n", optarg);
+				fprintf(stderr, "Invalid ID \"%s\"\n", optarg);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
 			break;
@@ -666,7 +666,7 @@ int main(int argc, char * argv[])
 			else if (!strcmp(optarg, "context-specific"))
 				opt_login_type = CKU_CONTEXT_SPECIFIC;
 			else {
-				printf("Unsupported login type \"%s\"\n", optarg);
+				fprintf(stderr, "Unsupported login type \"%s\"\n", optarg);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
 			break;
@@ -723,6 +723,9 @@ int main(int argc, char * argv[])
 			util_print_usage_and_die(app_name, options, option_help, NULL);
 		}
 	}
+	if (optind < argc) {
+		util_fatal("invalid option(s) given");
+	}
 
 	if (action_count == 0)
 		util_print_usage_and_die(app_name, options, option_help, NULL);
@@ -733,7 +736,7 @@ int main(int argc, char * argv[])
 
 	rv = p11->C_Initialize(NULL);
 	if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
-		printf("\n*** Cryptoki library has already been initialized ***\n");
+		fprintf(stderr, "\n*** Cryptoki library has already been initialized ***\n");
 	else if (rv != CKR_OK)
 		p11_fatal("C_Initialize", rv);
 
@@ -817,7 +820,7 @@ int main(int argc, char * argv[])
 
 		get_token_info(opt_slot, &info);
 		if (!(info.flags & CKF_TOKEN_INITIALIZED))
-			util_fatal("Token not initialized\n");
+			util_fatal("Token not initialized");
 		if (info.flags & CKF_LOGIN_REQUIRED)
 			opt_login++;
 	}
@@ -855,7 +858,7 @@ int main(int argc, char * argv[])
 	if (do_unlock_pin)   {
 		if (opt_login_type != -1
 				&& opt_login_type != CKU_CONTEXT_SPECIFIC)   {
-			printf("Invalid login type for 'Unlock User PIN' operation\n");
+			fprintf(stderr, "Invalid login type for 'Unlock User PIN' operation\n");
 			util_print_usage_and_die(app_name, options, option_help, NULL);
 		}
 
@@ -904,7 +907,7 @@ int main(int argc, char * argv[])
 
 	if (do_write_object) {
 		if (opt_object_class_str == NULL)
-			util_fatal("You should specify the object type with the -y option\n");
+			util_fatal("You should specify the object type with the -y option");
 		write_object(session);
 	}
 
@@ -915,7 +918,7 @@ int main(int argc, char * argv[])
 				opt_application_label == NULL && opt_application_id == NULL &&
 				opt_issuer == NULL && opt_subject == NULL)
 			 util_fatal("You should specify at least one of the "
-					 "object ID, object label, application label or application ID\n");
+					 "object ID, object label, application label or application ID");
 		read_object(session);
 	}
 
@@ -925,26 +928,34 @@ int main(int argc, char * argv[])
 		if (opt_object_id_len == 0 && opt_object_label == NULL &&
 				opt_application_label == NULL && opt_application_id == NULL)
 			 util_fatal("You should specify at least one of the "
-					 "object ID, object label, application label or application ID\n");
+					 "object ID, object label, application label or application ID");
 		delete_object(session);
 	}
 
 	if (do_set_id) {
 		if (opt_object_class_str == NULL)
-			util_fatal("You should specify the object type with the -y option\n");
+			util_fatal("You should specify the object type with the -y option");
 		if (opt_object_id_len == 0)
-			util_fatal("You should specify the current ID with the -d option\n");
+			util_fatal("You should specify the current ID with the -d option");
 		set_id_attr(session);
 	}
 
 	if (do_test)
 		p11_test(session);
 
-	if (do_test_kpgen_certwrite)
-		test_kpgen_certwrite(opt_slot, session);
+	if (do_test_kpgen_certwrite) {
+		if (!opt_login)
+			fprintf(stderr, "ERR: login required\n");
+		else
+			session = test_kpgen_certwrite(opt_slot, session);
+	}
 
-	if (do_test_ec)
-		test_ec(opt_slot, session);
+	if (do_test_ec) {
+		if (!opt_login)
+			fprintf(stderr, "ERR: login required\n");
+		else
+			test_ec(opt_slot, session);
+	}
 end:
 	if (session != CK_INVALID_HANDLE) {
 		rv = p11->C_CloseSession(session);
@@ -1186,7 +1197,7 @@ static int login(CK_SESSION_HANDLE session, int login_type)
 			printf("Please enter context specific PIN: ");
 		r = util_getpass(&pin, &len, stdin);
 		if (r < 0)
-			util_fatal("No PIN entered, exiting!\n");
+			util_fatal("No PIN entered");
 		pin_allocated = 1;
 	}
 
@@ -1215,7 +1226,7 @@ static void init_token(CK_SLOT_ID slot)
 	CK_RV rv;
 
 	if (!opt_object_label)
-		util_fatal("The token label must be specified using --label\n");
+		util_fatal("The token label must be specified using --label");
 	snprintf((char *) token_label, sizeof (token_label), "%-32.32s",
 			opt_object_label);
 
@@ -1227,18 +1238,18 @@ static void init_token(CK_SLOT_ID slot)
 			printf("Please enter the new SO PIN: ");
 			r = util_getpass(&new_pin, &len, stdin);
 			if (r < 0)
-				util_fatal("No PIN entered, exiting\n");
+				util_fatal("No PIN entered");
 			if (!new_pin || !*new_pin || strlen(new_pin) > 20)
-				util_fatal("Invalid SO PIN\n");
+				util_fatal("Invalid SO PIN");
 			strlcpy(new_buf, new_pin, sizeof new_buf);
 			free(new_pin); new_pin = NULL;
 			printf("Please enter the new SO PIN (again): ");
 			r = util_getpass(&new_pin, &len, stdin);
 			if (r < 0)
-				util_fatal("No PIN entered, exiting\n");
+				util_fatal("No PIN entered");
 			if (!new_pin || !*new_pin ||
 					strcmp(new_buf, new_pin) != 0)
-				util_fatal("Different new SO PINs, exiting\n");
+				util_fatal("Different new SO PINs");
 			pin_allocated = 1;
 		}
 	}
@@ -1269,16 +1280,16 @@ static void init_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess)
 			printf("Please enter the new PIN: ");
 			r = util_getpass(&new_pin1,&len1,stdin);
 			if (r < 0)
-				util_fatal("No PIN entered, aborting.\n");
+				util_fatal("No PIN entered");
 			if (!new_pin1 || !*new_pin1 || strlen(new_pin1) > 20)
-				util_fatal("Invalid User PIN\n");
+				util_fatal("Invalid User PIN");
 			printf("Please enter the new PIN again: ");
 			r = util_getpass(&new_pin2, &len2, stdin);
 			if (r < 0)
-				util_fatal("No PIN entered, aborting.\n");
+				util_fatal("No PIN entered");
 			if (!new_pin2 || !*new_pin2 ||
 					strcmp(new_pin1, new_pin2) != 0)
-				util_fatal("Different new User PINs, exiting\n");
+				util_fatal("Different new User PINs");
 		}
 	}
 
@@ -1444,7 +1455,7 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
 
 	if (!opt_mechanism_used)
 		if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism))
-			util_fatal("Sign mechanism not supported\n");
+			util_fatal("Sign mechanism not supported");
 
 	fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
 	memset(&mech, 0, sizeof(mech));
@@ -1503,7 +1514,7 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
 			size_t seqlen;
 
 			if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, sig_len, &seq, &seqlen)) {
-				util_fatal("Failed to convert signature to ASN.1 sequence format.");
+				util_fatal("Failed to convert signature to ASN.1 sequence format");
 			}
 
 			memcpy(sig_buffer, seq, seqlen);
@@ -1532,7 +1543,7 @@ static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
 
 	if (!opt_mechanism_used)
 		if (!find_mechanism(slot, CKF_DECRYPT|CKF_HW, NULL, 0, &opt_mechanism))
-			util_fatal("Decrypt mechanism not supported\n");
+			util_fatal("Decrypt mechanism not supported");
 
 	fprintf(stderr, "Using decrypt algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
 	memset(&mech, 0, sizeof(mech));
@@ -1587,7 +1598,7 @@ static void hash_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 
 	if (!opt_mechanism_used)
 		if (!find_mechanism(slot, CKF_DIGEST, NULL, 0, &opt_mechanism))
-			util_fatal("Digest mechanism is not supported\n");
+			util_fatal("Digest mechanism is not supported");
 
 	fprintf(stderr, "Using digest algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
 	memset(&mech, 0, sizeof(mech));
@@ -1664,7 +1675,7 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
 
 			if (!opt_mechanism_used)
 				if (!find_mechanism(slot, CKF_GENERATE_KEY_PAIR, mtypes, mtypes_num, &opt_mechanism))
-					util_fatal("Generate RSA mechanism not supported\n");
+					util_fatal("Generate RSA mechanism not supported");
 
 			if (size == NULL)
 				util_fatal("Unknown key type %s", type);
@@ -1719,7 +1730,7 @@ static int gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
 			if (!ecparams)
 				util_fatal("Allocation error", 0);
 			if (!hex_to_bin(ec_curve_infos[ii].oid_encoded, ecparams, &ecparams_size)) {
-				printf("Cannot convert \"%s\"\n", ec_curve_infos[ii].oid_encoded);
+				fprintf(stderr, "Cannot convert \"%s\"\n", ec_curve_infos[ii].oid_encoded);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
 
@@ -1866,13 +1877,17 @@ gen_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hSecretKey
 static void	parse_certificate(struct x509cert_info *cert,
 		unsigned char *data, int len)
 {
-	X509 *x;
+	X509 *x = NULL;
 	unsigned char *p;
-	const unsigned char *pp;
 	int n;
 
-	pp = data;
-	x = d2i_X509(NULL, &pp, len);
+	if (!strstr((char *)data, "-----BEGIN CERTIFICATE-----"))
+		x = d2i_X509(NULL, (const unsigned char **)&data, len);
+	else {
+		BIO *mem = BIO_new_mem_buf(data, len);
+		x = PEM_read_bio_X509(mem, NULL, NULL, NULL);
+		BIO_free(mem);
+	}
 	if (!x) {
 		util_fatal("OpenSSL error during X509 certificate parsing");
 	}
@@ -1913,20 +1928,10 @@ static void	parse_certificate(struct x509cert_info *cert,
 static int
 do_read_key(unsigned char *data, size_t data_len, int private, EVP_PKEY **key)
 {
-	BIO *mem;
-	BUF_MEM buf_mem;
+	BIO *mem = BIO_new_mem_buf(data, data_len);;
 
 	if (!key)
 		return -1;
-	buf_mem.data = malloc(data_len);
-	if (!buf_mem.data)
-		return -1;
-
-	memcpy(buf_mem.data, data, data_len);
-	buf_mem.max = buf_mem.length = data_len;
-
-	mem = BIO_new(BIO_s_mem());
-	BIO_set_mem_buf(mem, &buf_mem, BIO_NOCLOSE);
 
 	if (private) {
 		if (!strstr((char *)data, "-----BEGIN "))
@@ -1948,12 +1953,12 @@ do_read_key(unsigned char *data, size_t data_len, int private, EVP_PKEY **key)
 	return 0;
 }
 
-#define RSA_GET_BN(LOCALNAME, BNVALUE) \
+#define RSA_GET_BN(RSA, LOCALNAME, BNVALUE) \
 	do { \
-		rsa->LOCALNAME = malloc(BN_num_bytes(BNVALUE)); \
-		if (!rsa->LOCALNAME) \
-			util_fatal("malloc() failure\n"); \
-		rsa->LOCALNAME##_len = BN_bn2bin(BNVALUE, rsa->LOCALNAME); \
+		RSA->LOCALNAME = malloc(BN_num_bytes(BNVALUE)); \
+		if (!RSA->LOCALNAME) \
+			util_fatal("malloc() failure"); \
+		RSA->LOCALNAME##_len = BN_bn2bin(BNVALUE, RSA->LOCALNAME); \
 	} while (0)
 
 static int
@@ -1969,15 +1974,15 @@ parse_rsa_pkey(EVP_PKEY *pkey, int private, struct rsakey_info *rsa)
 			util_fatal("OpenSSL error during RSA public key parsing");
 	}
 
-	RSA_GET_BN(modulus, r->n);
-	RSA_GET_BN(public_exponent, r->e);
+	RSA_GET_BN(rsa, modulus, r->n);
+	RSA_GET_BN(rsa, public_exponent, r->e);
 	if (private) {
-		RSA_GET_BN(private_exponent, r->d);
-		RSA_GET_BN(prime_1, r->p);
-		RSA_GET_BN(prime_2, r->q);
-		RSA_GET_BN(exponent_1, r->dmp1);
-		RSA_GET_BN(exponent_2, r->dmq1);
-		RSA_GET_BN(coefficient, r->iqmp);
+		RSA_GET_BN(rsa, private_exponent, r->d);
+		RSA_GET_BN(rsa, prime_1, r->p);
+		RSA_GET_BN(rsa, prime_2, r->q);
+		RSA_GET_BN(rsa, exponent_1, r->dmp1);
+		RSA_GET_BN(rsa, exponent_2, r->dmq1);
+		RSA_GET_BN(rsa, coefficient, r->iqmp);
 	}
 
 	RSA_free(r);
@@ -2048,6 +2053,54 @@ parse_gost_pkey(EVP_PKEY *pkey, int private, struct gostkey_info *gost)
 
 	return 0;
 }
+
+static int
+parse_ec_pkey(EVP_PKEY *pkey, int private, struct gostkey_info *gost)
+{
+	EC_KEY *src = EVP_PKEY_get0(pkey);
+	const BIGNUM *bignum;
+
+	if (!src)
+		return -1;
+
+	gost->param_oid.len = i2d_ECParameters(src, &gost->param_oid.value);
+	if (gost->param_oid.len <= 0)
+		return -1;
+
+	if (private) {
+		bignum = EC_KEY_get0_private_key(EVP_PKEY_get0(pkey));
+
+		gost->private.len = BN_num_bytes(bignum);
+		gost->private.value = malloc(gost->private.len);
+		if (!gost->private.value)
+			return -1;
+		BN_bn2bin(bignum, gost->private.value);
+	}
+	else {
+		unsigned char buf[512], *point;
+		int point_len, header_len;
+		const int MAX_HEADER_LEN = 3;
+		const EC_GROUP *ecgroup = EC_KEY_get0_group(src);
+		const EC_POINT *ecpoint = EC_KEY_get0_public_key(src);
+		if (!ecgroup || !ecpoint)
+			return -1;
+		point_len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf), NULL);
+		gost->public.value = malloc(MAX_HEADER_LEN+point_len);
+		if (!gost->public.value)
+			return -1;
+		point = gost->public.value;
+		ASN1_put_object(&point, 0, point_len, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL);
+		header_len = point-gost->public.value;
+		memcpy(point, buf, point_len);
+		gost->public.len = header_len+point_len;
+#ifndef EC_POINT_NO_ASN1_OCTET_STRING // workaround for non-compliant cards not expecting DER encoding
+		gost->public.len   -= header_len;
+		gost->public.value += header_len;
+#endif
+	}
+
+	return 0;
+}
 #endif
 #endif
 
@@ -2073,8 +2126,8 @@ static int write_object(CK_SESSION_HANDLE session)
 	unsigned char *oid_buf = NULL;
 	CK_OBJECT_CLASS clazz;
 	CK_CERTIFICATE_TYPE cert_type;
-	CK_KEY_TYPE type = CKK_RSA;
 #ifdef ENABLE_OPENSSL
+	CK_KEY_TYPE type = CKK_RSA;
 	struct x509cert_info cert;
 	struct rsakey_info rsa;
 	struct gostkey_info gost;
@@ -2090,19 +2143,19 @@ static int write_object(CK_SESSION_HANDLE session)
 
 	f = fopen(opt_file_to_write, "rb");
 	if (f == NULL)
-		util_fatal("Couldn't open file \"%s\"\n", opt_file_to_write);
+		util_fatal("Couldn't open file \"%s\"", opt_file_to_write);
 	contents_len = fread(contents, 1, sizeof(contents) - 1, f);
 	if (contents_len < 0)
-		util_fatal("Couldn't read from file \"%s\"\n", opt_file_to_write);
+		util_fatal("Couldn't read from file \"%s\"", opt_file_to_write);
 	fclose(f);
 	contents[contents_len] = '\0';
 
 	if (opt_attr_from_file) {
 		if (!(f = fopen(opt_attr_from_file, "rb")))
-			util_fatal("Couldn't open file \"%s\"\n", opt_attr_from_file);
+			util_fatal("Couldn't open file \"%s\"", opt_attr_from_file);
 		certdata_len = fread(certdata, 1, sizeof(certdata), f);
 		if (certdata_len < 0)
-			util_fatal("Couldn't read from file \"%s\"\n", opt_attr_from_file);
+			util_fatal("Couldn't read from file \"%s\"", opt_attr_from_file);
 		fclose(f);
 		need_to_parse_certdata = 1;
 	}
@@ -2116,7 +2169,7 @@ static int write_object(CK_SESSION_HANDLE session)
 #ifdef ENABLE_OPENSSL
 		parse_certificate(&cert, certdata, certdata_len);
 #else
-		util_fatal("No OpenSSL support, cannot parse certificate\n");
+		util_fatal("No OpenSSL support, cannot parse certificate");
 #endif
 	}
 	if (opt_object_class == CKO_PRIVATE_KEY || opt_object_class == CKO_PUBLIC_KEY) {
@@ -2127,27 +2180,30 @@ static int write_object(CK_SESSION_HANDLE session)
 		rv = do_read_key(contents, contents_len, is_private, &evp_key);
 		if (rv) {
 			if (is_private)
-				util_fatal("Cannot read private key\n");
+				util_fatal("Cannot read private key");
 			else
-				util_fatal("Cannot read public key\n");
+				util_fatal("Cannot read public key");
 		}
 
 		if (evp_key->type == EVP_PKEY_RSA) {
 			rv = parse_rsa_pkey(evp_key, is_private, &rsa);
 		}
 #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
-		else if (evp_key->type == NID_id_GostR3410_2001 || evp_key->type == EVP_PKEY_EC)   {
-			/* parsing ECDSA is identical to GOST */
+		else if (evp_key->type == NID_id_GostR3410_2001) {
 			rv = parse_gost_pkey(evp_key, is_private, &gost);
+			type = CKK_GOSTR3410;
+		} else if (evp_key->type == EVP_PKEY_EC) {
+			rv = parse_ec_pkey(evp_key, is_private, &gost);
+			type = CKK_EC;
 		}
 #endif
 		else
-			util_fatal("Unsupported key type: 0x%X\n", evp_key->type);
+			util_fatal("Unsupported key type: 0x%X", evp_key->type);
 
 		if (rv)
-			util_fatal("Cannot parse key\n");
+			util_fatal("Cannot parse key");
 #else
-		util_fatal("No OpenSSL support, cannot parse key\n");
+		util_fatal("No OpenSSL support, cannot parse key");
 #endif
 	}
 
@@ -2220,9 +2276,9 @@ static int write_object(CK_SESSION_HANDLE session)
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_SUBJECT, cert.subject, cert.subject_len);
 			n_privkey_attr++;
 		}
+		FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
+		n_privkey_attr++;
 		if (evp_key->type == EVP_PKEY_RSA)   {
-			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
-			n_privkey_attr++;
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_MODULUS, rsa.modulus, rsa.modulus_len);
 			n_privkey_attr++;
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_PUBLIC_EXPONENT, rsa.public_exponent, rsa.public_exponent_len);
@@ -2242,20 +2298,12 @@ static int write_object(CK_SESSION_HANDLE session)
 		}
 #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
 		else if (evp_key->type == EVP_PKEY_EC)   {
-			type = CKK_EC;
-
-			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
-			n_privkey_attr++;
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_EC_PARAMS, gost.param_oid.value, gost.param_oid.len);
 			n_privkey_attr++;
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_VALUE, gost.private.value, gost.private.len);
 			n_privkey_attr++;
 		}
 		else if (evp_key->type == NID_id_GostR3410_2001)   {
-			type = CKK_GOSTR3410;
-
-			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
-			n_privkey_attr++;
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_GOSTR3410_PARAMS, gost.param_oid.value, gost.param_oid.len);
 			n_privkey_attr++;
 			FILL_ATTR(privkey_templ[n_privkey_attr], CKA_VALUE, gost.private.value, gost.private.len);
@@ -2265,13 +2313,25 @@ static int write_object(CK_SESSION_HANDLE session)
 				return rv;
 			n_privkey_attr++;
 		}
+
 #endif
 #endif
 	}
 	else
 	if (opt_object_class == CKO_PUBLIC_KEY) {
 		clazz = CKO_PUBLIC_KEY;
-		type = CKK_RSA;
+#ifdef ENABLE_OPENSSL
+		if (evp_key->type == EVP_PKEY_RSA)
+			type = CKK_RSA;
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
+		else if (evp_key->type == EVP_PKEY_EC)
+			type = CKK_EC;
+		else if (evp_key->type == NID_id_GostR3410_2001)
+			type = CKK_GOSTR3410;
+#endif
+		else
+			util_fatal("Unsupported public key type: 0x%X", evp_key->type);
+#endif
 
 		n_pubkey_attr = 0;
 		FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_CLASS, &clazz, sizeof(clazz));
@@ -2316,32 +2376,22 @@ static int write_object(CK_SESSION_HANDLE session)
 			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_SUBJECT, cert.subject, cert.subject_len);
 			n_pubkey_attr++;
 		}
+		FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
+		n_pubkey_attr++;
 		if (evp_key->type == EVP_PKEY_RSA) {
-			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
-			n_pubkey_attr++;
-			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_MODULUS,
-				rsa.modulus, rsa.modulus_len);
+			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_MODULUS, rsa.modulus, rsa.modulus_len);
 			n_pubkey_attr++;
-			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PUBLIC_EXPONENT,
-				rsa.public_exponent, rsa.public_exponent_len);
+			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PUBLIC_EXPONENT, rsa.public_exponent, rsa.public_exponent_len);
 			n_pubkey_attr++;
 		}
 #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
 		else if (evp_key->type == EVP_PKEY_EC)   {
-			type = CKK_EC;
-
-			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
-			n_pubkey_attr++;
 			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_EC_PARAMS, gost.param_oid.value, gost.param_oid.len);
 			n_pubkey_attr++;
-			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_VALUE, gost.public.value, gost.public.len);
+			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_EC_POINT, gost.public.value, gost.public.len);
 			n_pubkey_attr++;
 		}
 		else if (evp_key->type == NID_id_GostR3410_2001) {
-			type = CKK_GOSTR3410;
-
-			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
-			n_pubkey_attr++;
 			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_GOSTR3410_PARAMS, gost.param_oid.value, gost.param_oid.len);
 			n_pubkey_attr++;
 			FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_VALUE, gost.public.value, gost.public.len);
@@ -2382,10 +2432,10 @@ static int write_object(CK_SESSION_HANDLE session)
 			size_t len;
 
 			if (sc_format_oid(&oid, opt_application_id))
-				util_fatal("Invalid OID \"%s\"\n", opt_application_id);
+				util_fatal("Invalid OID \"%s\"", opt_application_id);
 
 			if (sc_asn1_encode_object_id(&oid_buf, &len, &oid))
-				util_fatal("Cannot encode OID \"%s\"\n", opt_application_id);
+				util_fatal("Cannot encode OID \"%s\"", opt_application_id);
 
 			FILL_ATTR(data_templ[n_data_attr], CKA_OBJECT_ID, oid_buf, len);
 			n_data_attr++;
@@ -2398,7 +2448,7 @@ static int write_object(CK_SESSION_HANDLE session)
 
 	}
 	else
-		util_fatal("Writing of a \"%s\" type not (yet) supported\n", opt_object_class_str);
+		util_fatal("Writing of a \"%s\" type not (yet) supported", opt_object_class_str);
 
 	if (n_data_attr) {
 		rv = p11->C_CreateObject(session, data_templ, n_data_attr, &data_obj);
@@ -2447,7 +2497,7 @@ static void set_id_attr(CK_SESSION_HANDLE session)
 	CK_RV rv;
 
 	if (!find_object(session, opt_object_class, &obj, opt_object_id, opt_object_id_len, 0)) {
-		printf("set_id(): coudn't find the object\n");
+		fprintf(stderr, "set_id(): couldn't find the object\n");
 		return;
 	}
 
@@ -2773,7 +2823,7 @@ derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
 	
 	if (!opt_mechanism_used)
 		if (!find_mechanism(slot, CKF_DERIVE|CKF_HW, NULL, 0, &opt_mechanism))
-			util_fatal("Derive mechanism not supported\n");
+			util_fatal("Derive mechanism not supported");
 
 	printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(opt_mechanism));
 	memset(&mech, 0, sizeof(mech));
@@ -2802,7 +2852,7 @@ derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
 		ecpoint = EC_KEY_get0_public_key(eckey);
 		ecgroup = EC_KEY_get0_group(eckey);
 		if (!ecpoint || !ecgroup)
-			util_fatal("Failed to parse other EC kry from %s", opt_input);
+			util_fatal("Failed to parse other EC key from %s", opt_input);
 
 		len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf),NULL);
 
@@ -2819,7 +2869,7 @@ derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
 #endif /* ENABLE_OPENSSL  && !OPENSSL_NO_EC && !OPENSSL_NO_ECDSA */
 	/* TODO add RSA  but do not have card to test */
 	default:
-		util_fatal("mechanisum not supported for derive\n");
+		util_fatal("mechanism not supported for derive");
 		break;
 	}
 
@@ -3194,6 +3244,26 @@ get_mechanisms(CK_SLOT_ID slot, CK_MECHANISM_TYPE_PTR *pList, CK_FLAGS flags)
 	return ulCount;
 }
 
+#ifdef ENABLE_OPENSSL
+unsigned char *BIO_copy_data(BIO *out, int *data_lenp) {
+    unsigned char *data, *tdata;
+    int data_len;
+
+    data_len = BIO_get_mem_data(out, &tdata);
+    data = malloc(data_len+1);
+    if (data) {
+        memcpy(data, tdata, data_len);
+	data[data_len]='\0';  // Make sure it's \0 terminated, in case used as string
+	if (data_lenp) {
+	    *data_lenp = data_len;
+	}
+    } else {
+        util_fatal("malloc failed");
+    }
+    return data;
+}
+#endif
+
 /*
  * Read object CKA_VALUE attribute's value.
  */
@@ -3202,6 +3272,9 @@ static int read_object(CK_SESSION_HANDLE session)
 	CK_RV rv;
 	CK_ATTRIBUTE attrs[20];
 	CK_OBJECT_CLASS clazz = opt_object_class;
+#ifdef ENABLE_OPENSSL
+	CK_KEY_TYPE type = CKK_RSA;
+#endif
 	CK_OBJECT_HANDLE obj = CK_INVALID_HANDLE;
 	int nn_attrs = 0;
 	unsigned char *value = NULL, *oid_buf = NULL;
@@ -3238,10 +3311,10 @@ static int read_object(CK_SESSION_HANDLE session)
 		size_t oid_buf_len;
 
 		if (sc_format_oid(&oid, opt_application_id))
-			util_fatal("Invalid OID \"%s\"\n", opt_application_id);
+			util_fatal("Invalid OID \"%s\"", opt_application_id);
 
 		if (sc_asn1_encode_object_id(&oid_buf, &oid_buf_len, &oid))
-			util_fatal("Cannot encode OID \"%s\"\n", opt_application_id);
+			util_fatal("Cannot encode OID \"%s\"", opt_application_id);
 
 		FILL_ATTR(attrs[nn_attrs], CKA_OBJECT_ID, oid_buf, oid_buf_len);
 		nn_attrs++;
@@ -3269,26 +3342,113 @@ static int read_object(CK_SESSION_HANDLE session)
 	if (rv != CKR_OK)
 		p11_fatal("find_object_with_attributes()", rv);
 	else if (obj==CK_INVALID_HANDLE)
-		util_fatal("object not found\n");
+		util_fatal("object not found");
 
 /* TODO: -DEE should look at object class, and get appropriate values
  * based on the object, and other attributes. For example EC keys do
- * not have a VALUE But have a EC_POINT.
+ * not have a VALUE But have a EC_POINT. DvO: done for RSA and EC public keys.
  */
-	value = getVALUE(session, obj, &len);
+	if (clazz == CKO_PRIVATE_KEY) {
+		fprintf(stderr, "sorry, reading private keys not (yet) supported\n");
+		return 0;
+	}
+	if (clazz == CKO_PUBLIC_KEY) {
+#ifdef ENABLE_OPENSSL
+		int derlen;
+		BIO *pout = BIO_new(BIO_s_mem());
+		if (!pout)
+			util_fatal("out of memory");
+
+		type = getKEY_TYPE(session, obj);
+		if (type == CKK_RSA) {
+			RSA *rsa;
+
+			rsa = RSA_new();
+			if (rsa == NULL)
+				util_fatal("out of memory");
+
+			if ((value = getMODULUS(session, obj, &len))) {
+				if (!(rsa->n = BN_bin2bn(value, len, rsa->n)))
+					util_fatal("cannot parse MODULUS");
+				free(value);
+			} else
+				util_fatal("cannot obtain MODULUS");
+
+			if ((value = getPUBLIC_EXPONENT(session, obj, &len))) {
+				if (!(rsa->e = BN_bin2bn(value, len, rsa->e)))
+					util_fatal("cannot parse PUBLIC_EXPONENT");
+				free(value);
+			} else
+				util_fatal("cannot obtain PUBLIC_EXPONENT");
+
+			if (!i2d_RSA_PUBKEY_bio(pout, rsa))
+				util_fatal("cannot convert RSA public key to DER");
+			RSA_free(rsa);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
+		} else if (type == CKK_EC) {
+			EC_KEY *ec;
+			CK_BYTE *params;
+			const unsigned char *a;
+			ASN1_OCTET_STRING *os;
+			EC_KEY *success = NULL;
+
+			ec = EC_KEY_new();
+			if (ec == NULL)
+				util_fatal("out of memory");
+
+			if ((params = getEC_PARAMS(session, obj, &len))) {
+				const unsigned char *a = params;
+				if (!d2i_ECParameters(&ec, &a, (long)len))
+					util_fatal("cannot parse EC_PARAMS");
+				OPENSSL_free(params);
+			} else
+				util_fatal("cannot obtain EC_PARAMS");
+
+			value = getEC_POINT(session, obj, &len);
+			/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
+			a = value;
+			os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len);
+			if (os) {
+				a = os->data;
+				success = o2i_ECPublicKey(&ec, &a, os->length);
+				ASN1_STRING_free(os);
+			}
+			if (!success) { /* Workaround for broken PKCS#11 modules */
+				a = value;
+				success = o2i_ECPublicKey(&ec, &a, len);
+			}
+			free(value);
+			if (!success)
+				util_fatal("cannot obtain and parse EC_POINT");
+			if (!i2d_EC_PUBKEY_bio(pout, ec))
+				util_fatal("cannot convert EC public key to DER");
+			EC_KEY_free(ec);
+#endif
+		}
+		else
+			util_fatal("Reading public keys of type 0x%X not (yet) supported", type);
+		value = BIO_copy_data(pout, &derlen);
+		BIO_free(pout);
+		len = derlen;
+#else
+		util_fatal("No OpenSSL support, cannot read public key");
+#endif
+	}
+	else
+		value = getVALUE(session, obj, &len);
 	if (value == NULL)
-		util_fatal("get CKA_VALUE failed\n");
+		util_fatal("get CKA_VALUE failed");
 
 	if (opt_output)   {
 		out = fopen(opt_output, "wb");
 		if (out==NULL)
-			util_fatal("cannot open '%s'\n", opt_output);
+			util_fatal("cannot open '%s'", opt_output);
 	}
 	else
 		out = stdout;
 
 	if (fwrite(value, 1, len, out) != len)
-		util_fatal("cannot write to '%s'\n", opt_output);
+		util_fatal("cannot write to '%s'", opt_output);
 	if (opt_output)
 		fclose(out);
 
@@ -3338,10 +3498,10 @@ static int delete_object(CK_SESSION_HANDLE session)
 		size_t oid_buf_len;
 
 		if (sc_format_oid(&oid, opt_application_id))
-			util_fatal("Invalid OID '%s'\n", opt_application_id);
+			util_fatal("Invalid OID '%s'", opt_application_id);
 
 		if (sc_asn1_encode_object_id(&oid_buf, &oid_buf_len, &oid))
-			util_fatal("Cannot encode OID \"%s\"\n", opt_application_id);
+			util_fatal("Cannot encode OID \"%s\"", opt_application_id);
 
 		FILL_ATTR(attrs[nn_attrs], CKA_OBJECT_ID, oid_buf, oid_buf_len);
 		nn_attrs++;
@@ -3351,7 +3511,7 @@ static int delete_object(CK_SESSION_HANDLE session)
 	if (rv != CKR_OK)
 		p11_fatal("find_object_with_attributes()", rv);
 	else if (obj==CK_INVALID_HANDLE)
-		util_fatal("object not found\n");
+		util_fatal("object not found");
 	rv = p11->C_DestroyObject(session, obj);
 	if (rv != CKR_OK)
 		p11_fatal("C_DestroyObject()", rv);
@@ -3371,13 +3531,13 @@ static CK_ULONG	get_private_key_length(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE
 	id = NULL;
 	id = getID(sess, prkey, &idLen);
 	if (id == NULL) {
-		printf("private key has no ID, can't lookup the corresponding pubkey\n");
+		fprintf(stderr, "private key has no ID, can't lookup the corresponding pubkey\n");
 		return 0;
 	}
 
 	if (!find_object(sess, CKO_PUBLIC_KEY, &pubkey, id, idLen, 0)) {
 		free(id);
-		printf("coudn't find the corresponding pubkey\n");
+		fprintf(stderr, "couldn't find the corresponding pubkey\n");
 		return 0;
 	}
 	free(id);
@@ -3419,7 +3579,7 @@ static int test_digest(CK_SESSION_HANDLE session)
 		p11_fatal("C_OpenSession", rv);
 
 	if (!find_mechanism(sessionInfo.slotID, CKF_DIGEST, NULL, 0, &firstMechType)) {
-		printf("Digests: not implemented\n");
+		fprintf(stderr, "Digests: not implemented\n");
 		return errors;
 	}
 	else    {
@@ -3562,13 +3722,13 @@ static EVP_PKEY *get_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv
 	id = NULL;
 	id = getID(session, privKeyObject, &idLen);
 	if (id == NULL) {
-		printf("private key has no ID, can't lookup the corresponding pubkey for verification\n");
+		fprintf(stderr, "private key has no ID, can't lookup the corresponding pubkey for verification\n");
 		return NULL;
 	}
 
 	if (!find_object(session, CKO_PUBLIC_KEY, &pubkeyObject, id, idLen, 0)) {
 		free(id);
-		printf("coudn't find the corresponding pubkey for validation\n");
+		fprintf(stderr, "couldn't find the corresponding pubkey for validation\n");
 		return NULL;
 	}
 	free(id);
@@ -3580,7 +3740,7 @@ static EVP_PKEY *get_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv
 			mod = getMODULUS(session, pubkeyObject, &modLen);
 			exp = getPUBLIC_EXPONENT(session, pubkeyObject, &expLen);
 			if ( !pkey || !rsa || !mod || !exp) {
-				printf("public key not extractable\n");
+				fprintf(stderr, "public key not extractable\n");
 				if (pkey)
 					EVP_PKEY_free(pkey);
 				if (rsa)
@@ -3602,13 +3762,13 @@ static EVP_PKEY *get_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv
 		case CKK_GOSTR3410:
 			break;
 		default:
-			printf("public key of unsupported type\n");
+			fprintf(stderr, "public key of unsupported type\n");
 			return NULL;
 	}
 
 	pubkey = getVALUE(session, pubkeyObject, &pubkeyLen);
 	if (pubkey == NULL) {
-		printf("couldn't get the pubkey VALUE attribute, no validation done\n");
+		fprintf(stderr, "couldn't get the pubkey VALUE attribute, no validation done\n");
 		return NULL;
 	}
 
@@ -3617,7 +3777,7 @@ static EVP_PKEY *get_public_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE priv
 	free(pubkey);
 
 	if (pkey == NULL) {
-		printf(" couldn't parse pubkey, no verification done\n");
+		fprintf(stderr, "couldn't parse pubkey, no verification done\n");
 		return NULL;
 	}
 
@@ -3677,7 +3837,7 @@ static int sign_verify_openssl(CK_SESSION_HANDLE session,
 				(unsigned int) modLenBytes);
 	}
 #ifndef ENABLE_OPENSSL
-	printf("unable to verify signature (compile with ENABLE_OPENSSL)\n");
+	fprintf(stderr, "unable to verify signature (compile with ENABLE_OPENSSL)\n");
 #else
 
 	if (!(pkey = get_public_key(session, privKeyObject)))
@@ -3775,13 +3935,17 @@ static int test_signature(CK_SESSION_HANDLE sess)
 		return errors;
 	}
 
-	printf("Signatures (currently only RSA signatures)\n");
+	printf("Signatures (currently only for RSA)\n");
 	for (j = 0; find_object(sess, CKO_PRIVATE_KEY, &privKeyObject, NULL, 0, j); j++) {
 		printf("  testing key %ld ", j);
 		if ((label = getLABEL(sess, privKeyObject, NULL)) != NULL) {
 			printf("(%s) ", label);
 			free(label);
 		}
+		if (getKEY_TYPE(sess, privKeyObject) != CKK_RSA) {
+			printf(" -- non-RSA, skipping\n");
+			continue;
+		}
 
 		if (!getSIGN(sess, privKeyObject)) {
 			printf(" -- can't be used for signature, skipping\n");
@@ -3797,7 +3961,7 @@ static int test_signature(CK_SESSION_HANDLE sess)
 		break;
 	}
 	if (privKeyObject == CK_INVALID_HANDLE) {
-		printf("Signatures: no private key found in this slot\n");
+		fprintf(stderr, "Signatures: no private key found in this slot\n");
 		return 0;
 	}
 
@@ -3948,6 +4112,10 @@ static int test_signature(CK_SESSION_HANDLE sess)
 		if (label)
 			free(label);
 
+		if (getKEY_TYPE(sess, privKeyObject) != CKK_RSA) {
+			printf(" -- non-RSA, skipping\n");
+			continue;
+		}
 		if (!getSIGN(sess, privKeyObject)) {
 			printf(" -- can't be used to sign/verify, skipping\n");
 			continue;
@@ -4070,7 +4238,7 @@ static int test_verify(CK_SESSION_HANDLE sess)
 		return errors;
 	}
 
-	printf("Verify (currently only for RSA):\n");
+	printf("Verify (currently only for RSA)\n");
 
 	for (i = 0; find_object(sess, CKO_PRIVATE_KEY, &priv_key, NULL, 0, i); i++) {
 		char *label;
@@ -4084,7 +4252,10 @@ static int test_verify(CK_SESSION_HANDLE sess)
 		}
 		if (i != 0)
 			printf(" with 1 mechanism");
-		printf("\n");
+		if (getKEY_TYPE(sess, priv_key) != CKK_RSA) {
+			printf(" -- non-RSA, skipping\n");
+			continue;
+		}
 
 		if (!getSIGN(sess, priv_key)) {
 			printf(" -- can't be used to sign/verify, skipping\n");
@@ -4146,21 +4317,21 @@ static int wrap_unwrap(CK_SESSION_HANDLE session,
 	if (!EVP_SealInit(&seal_ctx, algo,
 			&key, &key_len,
 			iv, &pkey, 1)) {
-		printf("Internal error.\n");
+		fprintf(stderr, "Internal error.\n");
 		return 1;
 	}
 
 	/* Encrypt something */
 	len = sizeof(ciphered);
 	if (!EVP_SealUpdate(&seal_ctx, ciphered, &len, (const unsigned char *) "hello world", 11)) {
-		printf("Internal error.\n");
+		fprintf(stderr, "Internal error.\n");
 		return 1;
 	}
 	ciphered_len = len;
 
 	len = sizeof(ciphered) - ciphered_len;
 	if (!EVP_SealFinal(&seal_ctx, ciphered + ciphered_len, &len)) {
-		printf("Internal error.\n");
+		fprintf(stderr, "Internal error.\n");
 		return 1;
 	}
 	ciphered_len += len;
@@ -4187,30 +4358,30 @@ static int wrap_unwrap(CK_SESSION_HANDLE session,
 	key = getVALUE(session, cipherKeyObject, &key_len_ul);
 	key_len = key_len_ul;
 	if (key == NULL) {
-		printf("Could not get unwrapped key\n");
+		fprintf(stderr, "Could not get unwrapped key\n");
 		return 1;
 	}
 	if (key_len != EVP_CIPHER_key_length(algo)) {
-		printf("Key length mismatch (%d != %d)\n",
+		fprintf(stderr, "Key length mismatch (%d != %d)\n",
 				key_len, EVP_CIPHER_key_length(algo));
 		return 1;
 	}
 
 	if (!EVP_DecryptInit(&seal_ctx, algo, key, iv)) {
-		printf("Internal error.\n");
+		fprintf(stderr, "Internal error.\n");
 		return 1;
 	}
 
 	len = sizeof(cleartext);
 	if (!EVP_DecryptUpdate(&seal_ctx, cleartext, &len, ciphered, ciphered_len)) {
-		printf("Internal error.\n");
+		fprintf(stderr, "Internal error.\n");
 		return 1;
 	}
 
 	cleartext_len = len;
 	len = sizeof(cleartext) - len;
 	if (!EVP_DecryptFinal(&seal_ctx, cleartext + cleartext_len, &len)) {
-		printf("Internal error.\n");
+		fprintf(stderr, "Internal error.\n");
 		return 1;
 	}
 	cleartext_len += len;
@@ -4253,13 +4424,17 @@ static int test_unwrap(CK_SESSION_HANDLE sess)
 		return errors;
 	}
 
-	printf("Key unwrap (RSA)\n");
+	printf("Key unwrap (currently only for RSA)\n");
 	for (j = 0; find_object(sess, CKO_PRIVATE_KEY, &privKeyObject, NULL, 0, j); j++) {
 		printf("  testing key %ld ", j);
 		if ((label = getLABEL(sess, privKeyObject, NULL)) != NULL) {
 			printf("(%s) ", label);
 			free(label);
 		}
+		if (getKEY_TYPE(sess, privKeyObject) != CKK_RSA) {
+			printf(" -- non-RSA, skipping\n");
+			continue;
+		}
 		if (!getUNWRAP(sess, privKeyObject)) {
 			printf(" -- can't be used to unwrap, skipping\n");
 			continue;
@@ -4299,7 +4474,7 @@ static int encrypt_decrypt(CK_SESSION_HANDLE session,
 		return 0;
 
 	if (EVP_PKEY_size(pkey) > (int)sizeof(encrypted)) {
-		printf("Ciphertext buffer too small\n");
+		fprintf(stderr, "Ciphertext buffer too small\n");
 		EVP_PKEY_free(pkey);
 		return 0;
 	}
@@ -4310,14 +4485,14 @@ static int encrypt_decrypt(CK_SESSION_HANDLE session,
 #endif
 	EVP_PKEY_free(pkey);
 	if (encrypted_len <= 0) {
-		printf("Encryption failed, returning\n");
+		fprintf(stderr, "Encryption failed, returning\n");
 		return 0;
 	}
 
 	mech.mechanism = mech_type;
 	rv = p11->C_DecryptInit(session, &mech, privKeyObject);
 	if (rv == CKR_MECHANISM_INVALID) {
-		printf("Mechanism not supported\n");
+		fprintf(stderr, "Mechanism not supported\n");
 		return 0;
 	}
 	if (rv != CKR_OK)
@@ -4365,7 +4540,10 @@ static int test_decrypt(CK_SESSION_HANDLE sess)
 	CK_OBJECT_HANDLE privKeyObject;
 	CK_MECHANISM_TYPE *mechs = NULL;
 	CK_SESSION_INFO sessionInfo;
-	CK_ULONG        j, n, num_mechs = 0;
+	CK_ULONG        j, num_mechs = 0;
+#ifdef ENABLE_OPENSSL
+	CK_ULONG        n;
+#endif
 	char 		*label;
 
 	rv = p11->C_GetSessionInfo(sess, &sessionInfo);
@@ -4382,13 +4560,17 @@ static int test_decrypt(CK_SESSION_HANDLE sess)
 		return errors;
 	}
 
-	printf("Decryption (RSA)\n");
+	printf("Decryption (currently only for RSA)\n");
 	for (j = 0; find_object(sess, CKO_PRIVATE_KEY, &privKeyObject, NULL, 0, j); j++) {
 		printf("  testing key %ld ", j);
 		if ((label = getLABEL(sess, privKeyObject, NULL)) != NULL) {
 			printf("(%s) ", label);
 			free(label);
 		}
+		if (getKEY_TYPE(sess, privKeyObject) != CKK_RSA) {
+			printf(" -- non-RSA, skipping\n");
+			continue;
+		}
 		if (!getDECRYPT(sess, privKeyObject)) {
 			printf(" -- can't be used to decrypt, skipping\n");
 			continue;
@@ -4397,7 +4579,6 @@ static int test_decrypt(CK_SESSION_HANDLE sess)
 
 #ifndef ENABLE_OPENSSL
 		printf("No OpenSSL support, unable to validate decryption\n");
-		n = 0;
 #else
 		for (n = 0; n < num_mechs; n++) {
 			errors += encrypt_decrypt(sess, mechs[n], privKeyObject);
@@ -4527,7 +4708,7 @@ static int p11_test(CK_SESSION_HANDLE session)
  * cert request + some other tests, writing certs and changing
  * some attributes.
  */
-static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
+static CK_SESSION_HANDLE test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 {
 	CK_MECHANISM		mech = {CKM_RSA_PKCS, NULL_PTR, 0};
 	CK_MECHANISM_TYPE	*mech_type = NULL;
@@ -4538,7 +4719,7 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 	CK_BYTE			md5_and_digestinfo[34] = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10";
 	CK_BYTE			*data, sig[512];
 	CK_ULONG		data_len, sig_len;
-	CK_BYTE 		id[] = "abcdefghijklmnopqrst";
+	CK_BYTE			id[] = "abcdefghijklmnopqrst";
 	CK_ULONG		id_len = 20, mod_len = 0;
 	CK_BYTE			*label = (CK_BYTE *) "Just a label";
 	CK_ULONG		label_len = 12;
@@ -4547,8 +4728,16 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 		{CKA_LABEL, label, label_len},
 		{CKA_SUBJECT, (void *) "This won't be used in our lib", 29}
 	};
-	FILE                    *f;
+	FILE			*f;
 
+	if (!opt_object_id_len) {
+		fprintf(stderr, "ERR: must give an ID, e.g.: --id 01\n");
+		return session;
+	}
+	if (!opt_key_type) {
+		printf("ERR: must give an RSA key type, e.g.: --key-type RSA:1024\n");
+		return session;
+	}
 	printf("\n*** We already opened a session and logged in ***\n");
 
 	num_mechs = get_mechanisms(slot, &mech_type, -1);
@@ -4557,13 +4746,13 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 			break;
 	}
 	if (i == num_mechs) {
-		printf("ERR: no \"CKM_RSA_PKCS_KEY_PAIR_GEN\" found in the mechanism list\n");
-		return;
+		fprintf(stderr, "ERR: no \"CKM_RSA_PKCS_KEY_PAIR_GEN\" found in the mechanism list\n");
+		return session;
 	}
 
 	f = fopen(opt_file_to_write, "rb");
 	if (f == NULL)
-		util_fatal("Couldn't open file \"%s\"\n", opt_file_to_write);
+		util_fatal("Couldn't open file \"%s\"", opt_file_to_write);
 	fclose(f);
 
 	/* Get for a not-yet-existing ID */
@@ -4572,21 +4761,23 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 
 	printf("\n*** Generating a %s key pair ***\n", opt_key_type);
 
-	if (!gen_keypair(slot, session, &pub_key, &priv_key, opt_key_type))
-		return;
+	if (!gen_keypair(slot, session, &pub_key, &priv_key, opt_key_type)) {
+		printf("ERR: cannot generate new key pair\n");
+		return session;
+	}
 
 	tmp = getID(session, priv_key, (CK_ULONG *) &opt_object_id_len);
 	if (opt_object_id_len == 0) {
-		printf("ERR: newly generated private key has no (or an empty) CKA_ID\n");
-		return;
+		fprintf(stderr, "ERR: newly generated private key has no (or an empty) CKA_ID\n");
+		return session;
 	}
 	memcpy(opt_object_id, tmp, opt_object_id_len);
 
 	/* This is done in NSS */
 	getMODULUS(session, priv_key, &mod_len);
 	if (mod_len < 5 || mod_len > 10000) { /* should be resonable limits */
-		printf("ERR: GetAttribute(privkey, CKA_MODULUS) doesn't seem to work\n");
-		return;
+		fprintf(stderr, "ERR: GetAttribute(privkey, CKA_MODULUS) doesn't seem to work\n");
+		return session;
 	}
 
 	printf("\n*** Changing the CKA_ID of private and public key into one of 20 bytes ***\n");
@@ -4612,8 +4803,8 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 	sig_len = 20;
 	rv = p11->C_Sign(session, data, data_len, sig, &sig_len);
 	if (rv != CKR_BUFFER_TOO_SMALL) {
-		printf("ERR: C_Sign() didn't return CKR_BUFFER_TO_SMALL but %s\n", CKR2Str(rv));
-		return;
+		fprintf(stderr, "ERR: C_Sign() didn't return CKR_BUFFER_TO_SMALL but %s\n", CKR2Str(rv));
+		return session;
 	}
 	rv = p11->C_Sign(session, data, data_len, sig, &sig_len);
 	if (rv != CKR_OK)
@@ -4645,6 +4836,15 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 	if (rv != CKR_OK)
 		p11_fatal("C_SetAttributeValue", rv);
 
+	printf("*** Deleting the private and the public key again ***\n");
+
+	rv = p11->C_DestroyObject(session, priv_key);
+	if (rv != CKR_OK)
+		p11_fatal("C_DestroyObject()", rv);
+	rv = p11->C_DestroyObject(session, pub_key);
+	if (rv != CKR_OK)
+		p11_fatal("C_DestroyObject()", rv);
+
 	printf("\n*** Logging off and releasing pkcs11 lib ***\n");
 
 	rv = p11->C_CloseAllSessions(slot);
@@ -4688,9 +4888,12 @@ static void test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 	opt_object_id_len = id_len;
 	opt_object_label = (char *) label;
 	if (!write_object(session))
-		return;
+		util_fatal("Failed to write certificate");
+	if (!delete_object(session))
+		util_fatal("Failed to delete certificate");
 
 	printf("\n==> OK, successfull! Should work with Mozilla\n");
+	return session;
 }
 
 
@@ -4715,6 +4918,15 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 		{CKA_SUBJECT, (void *) "This won't be used in our lib", 29}
 	};
 
+	if (!opt_object_id_len) {
+		fprintf(stderr, "ERR: must give an ID, e.g.: --id 01\n");
+		return;
+	}
+	if (!opt_key_type) {
+		fprintf(stderr, "ERR: must give an EC key type, e.g.: --key-type EC:secp256r1\n");
+		return;
+	}
+
 	printf("\n*** We already opened a session and logged in ***\n");
 
 	num_mechs = get_mechanisms(slot, &mech_type, -1);
@@ -4722,8 +4934,8 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 		if (mech_type[i] == CKM_EC_KEY_PAIR_GEN)
 			break;
 	if (i == num_mechs) {
-		printf("ERR: no 'CKM_EC_KEY_PAIR_GEN' found in the mechanism list\n");
-		return;
+		printf("warning: no 'CKM_EC_KEY_PAIR_GEN' found in the mechanism list\n");
+		//return;
 	}
 
 	printf("*** Generating EC key pair ***\n");
@@ -4752,28 +4964,36 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 	printf("*** Changing the CKA_ID of private and public key into one of 20 bytes ***\n");
 	rv = p11->C_SetAttributeValue(session, priv_key, attribs, 1);
 	if (rv != CKR_OK)
-		p11_fatal("C_SetAttributeValue(priv_key)", rv);
+		p11_warn("C_SetAttributeValue(priv_key)", rv);
 
 	rv = p11->C_SetAttributeValue(session, pub_key, attribs, 1);
 	if (rv != CKR_OK)
-		p11_fatal("C_SetAttributeValue(pub_key)", rv);
-
+		p11_warn("C_SetAttributeValue(pub_key)", rv);
 
-	printf("*** Do a signature ***\n");
+	printf("*** Doing a signature ***\n");
 	data = data_to_sign;
-	data_len = sizeof(data_to_sign);
+	data_len = strlen((char *)data_to_sign);
 	rv = p11->C_SignInit(session, &mech, priv_key);
 	if (rv != CKR_OK)
 		p11_fatal("C_SignInit", rv);
 	rv = p11->C_Sign(session, data, data_len, NULL, &sig_len);
 	if (rv != CKR_OK)
 		p11_fatal("C_Sign", rv);
-	sig_len = 20;
+	sig_len -= 20;
 	rv = p11->C_Sign(session, data, data_len, sig, &sig_len);
 	if (rv != CKR_BUFFER_TOO_SMALL) {
-		printf("ERR: C_Sign() didn't return CKR_BUFFER_TO_SMALL but %s\n", CKR2Str(rv));
-		return;
+		printf("warning: C_Sign() didn't return CKR_BUFFER_TO_SMALL but %s\n", CKR2Str(rv));
+		// return;
+	}
+	sig_len += 20;
+	// re-doing C_SignInit after C_SignFinal to avoid CKR_OPERATION_NOT_INITIALIZED for CardOS
+	rv = p11->C_SignFinal(session, sig, &sig_len);
+	if (rv != CKR_OK) {
+		p11_warn("C_SignFinal", rv);
 	}
+	rv = p11->C_SignInit(session, &mech, priv_key);
+	if (rv != CKR_OK)
+		p11_fatal("C_SignInit", rv);
 	rv = p11->C_Sign(session, data, data_len, sig, &sig_len);
 	if (rv != CKR_OK)
 		p11_fatal("C_Sign", rv);
@@ -4781,7 +5001,15 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
 	printf("*** Changing the CKA_LABEL, CKA_ID and CKA_SUBJECT of the public key ***\n");
 	rv = p11->C_SetAttributeValue(session, pub_key, attribs, 3);
 	if (rv != CKR_OK)
-		p11_fatal("C_SetAttributeValue", rv);
+		p11_warn("C_SetAttributeValue(pub_key)", rv);
+
+	printf("*** Deleting the private and the public key again ***\n");
+	rv = p11->C_DestroyObject(session, priv_key);
+	if (rv != CKR_OK)
+		p11_fatal("C_DestroyObject()", rv);
+	rv = p11->C_DestroyObject(session, pub_key);
+	if (rv != CKR_OK)
+		p11_fatal("C_DestroyObject()", rv);
 
 	printf("==> OK\n");
 }
@@ -4890,7 +5118,7 @@ static void p11_fatal(const char *func, CK_RV rv)
 	if (module)
 		C_UnloadModule(module);
 
-	util_fatal("PKCS11 function %s failed: rv = %s (0x%0x)\n", func, CKR2Str(rv), (unsigned int) rv);
+	util_fatal("PKCS11 function %s failed: rv = %s (0x%0x)", func, CKR2Str(rv), (unsigned int) rv);
 }
 
 static void p11_warn(const char *func, CK_RV rv)
@@ -4907,6 +5135,7 @@ static void p11_perror(const char *msg, CK_RV rv)
 static int hex_to_bin(const char *in, unsigned char *out, size_t *outlen)
 {
 	size_t left, count = 0;
+	int nybbles = 2;
 
 	if (in == NULL || *in == '\0') {
 		*outlen = 0;
@@ -4915,8 +5144,11 @@ static int hex_to_bin(const char *in, unsigned char *out, size_t *outlen)
 
 	left = *outlen;
 
+	while (*in == '0' && *(++in) != '\0') ; // strip leading zeros in input
+	if (strlen(in) % 2)
+		nybbles = 1; // any leading zero in output should be in most-significant byte, not last one!
 	while (*in != '\0') {
-		int byte = 0, nybbles = 2;
+		int byte = 0;
 
 		while (nybbles-- && *in && *in != ':') {
 			char c;
@@ -4931,7 +5163,7 @@ static int hex_to_bin(const char *in, unsigned char *out, size_t *outlen)
 			if ('A' <= c && c <= 'F')
 				c = c - 'A' + 10;
 			else {
-				printf("hex_to_bin(): invalid char '%c' in hex string\n", c);
+				fprintf(stderr, "hex_to_bin(): invalid char '%c' in hex string\n", c);
 				*outlen = 0;
 				return 0;
 			}
@@ -4940,12 +5172,13 @@ static int hex_to_bin(const char *in, unsigned char *out, size_t *outlen)
 		if (*in == ':')
 			in++;
 		if (left <= 0) {
-			printf("hex_to_bin(): hex string too long");
+			fprintf(stderr, "hex_to_bin(): hex string too long");
 			*outlen = 0;
 			return 0;
 		}
 		out[count++] = (unsigned char) byte;
 		left--;
+		nybbles = 2;
 	}
 
 	*outlen = count;
@@ -5128,6 +5361,10 @@ static struct mech_info	p11_mechanisms[] = {
       { CKM_ECDSA_KEY_PAIR_GEN,	"ECDSA-KEY-PAIR-GEN", NULL },
       { CKM_ECDSA,		"ECDSA", NULL },
       { CKM_ECDSA_SHA1,		"ECDSA-SHA1", NULL },
+      { CKM_ECDSA_SHA224,	"ECDSA-SHA224", NULL },
+      { CKM_ECDSA_SHA256,	"ECDSA-SHA256", NULL },
+      { CKM_ECDSA_SHA384,	"ECDSA-SHA348", NULL },
+      { CKM_ECDSA_SHA512,	"ECDSA-SHA512", NULL },
       { CKM_ECDH1_DERIVE,	"ECDH1-DERIVE", NULL },
       { CKM_ECDH1_COFACTOR_DERIVE,"ECDH1-COFACTOR-DERIVE", NULL },
       { CKM_ECMQV_DERIVE,	"ECMQV-DERIVE", NULL },
@@ -5176,7 +5413,7 @@ static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *name)
 		 || (mi->short_name && !strcasecmp(mi->short_name, name)))
 			return mi->mech;
 	}
-	util_fatal("Unknown PKCS11 mechanism \"%s\"\n", name);
+	util_fatal("Unknown PKCS11 mechanism \"%s\"", name);
 	return 0; /* gcc food */
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git



More information about the pkg-opensc-commit mailing list