opensc-sys 0.1.1

FFI bindings to OpenSC
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
/*
 * pkcs15-sec.c: PKCS#15 cryptography functions
 *
 * Copyright (C) 2001, 2002  Juha Yrjölä <juha.yrjola@iki.fi>
 * Copyright (C) 2007        Nils Larsch <nils@larsch.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "internal.h"
#include "pkcs15.h"
#include "pkcs11/pkcs11.h"

static int sec_env_add_param(sc_security_env_t* se, const sc_sec_env_param_t* p)
{
	size_t i;

	if (!se || !p)
	    return SC_ERROR_INCORRECT_PARAMETERS;

	for (i = 0; i < SC_SEC_ENV_MAX_PARAMS; i++) {
	    if (se->params[i].value == NULL) {
		se->params[i] = *p;

		return SC_SUCCESS;
	    }
	}

	return SC_ERROR_TOO_MANY_OBJECTS;
}


static int get_file_path(const struct sc_pkcs15_object* obj, sc_path_t* path)
{
	if (!path)
		return SC_ERROR_INCORRECT_PARAMETERS;

	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
	const struct sc_pkcs15_skey_info *skey = (const struct sc_pkcs15_skey_info *) obj->data;

	if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) {
		*path = prkey->path;
	}
	else if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_SKEY) {
		*path = skey->path;
	}
	else
		return SC_ERROR_INCORRECT_PARAMETERS;

	return SC_SUCCESS;
}


static int select_key_file(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *key,
		sc_security_env_t *senv)
{
	sc_context_t *ctx = p15card->card->ctx;
	sc_path_t orig_path;
	sc_path_t path, file_id;
	int r;

	LOG_FUNC_CALLED(ctx);

	LOG_TEST_RET(ctx, get_file_path(key, &orig_path), "Could not get key file path.");
	memset(&path, 0, sizeof(sc_path_t));
	memset(&file_id, 0, sizeof(sc_path_t));

	/* TODO: Why file_app may be NULL -- at least 3F00 has to be present?
	 * Check validity of the following assumption. */
	/* For pkcs15-emulated cards, the file_app may be NULL,
	 * in that case we always assume an absolute path */
	if (!orig_path.len && orig_path.aid.len) {
		/* Private key is a SDO allocated in application DF */
		path = orig_path;
	}
	else if (orig_path.len == 2 && p15card->file_app != NULL) {
		/* Path is relative to app. DF */
		path = p15card->file_app->path;
		file_id = orig_path;
		sc_append_path(&path, &file_id);
		senv->file_ref = file_id;
		senv->flags |= SC_SEC_ENV_FILE_REF_PRESENT;
	}
	else if (orig_path.len > 2) {
		path = orig_path;
		memcpy(file_id.value, orig_path.value + orig_path.len - 2, 2);
		file_id.len = 2;
		file_id.type = SC_PATH_TYPE_FILE_ID;
		senv->file_ref = file_id;
		senv->flags |= SC_SEC_ENV_FILE_REF_PRESENT;
	}
	else {
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "invalid private key path");
	}

	r = sc_select_file(p15card->card, &path, NULL);
	LOG_TEST_RET(ctx, r, "sc_select_file() failed");

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}

static int use_key(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *obj,
		sc_security_env_t *senv,
		int (*card_command)(sc_card_t *card,
			 const u8 * in, size_t inlen,
			 u8 * out, size_t outlen),
		const u8 * in, size_t inlen, u8 * out, size_t outlen)
{
	int r = SC_SUCCESS;
	int revalidated_cached_pin = 0;
	sc_path_t path;
	LOG_TEST_RET(p15card->card->ctx, get_file_path(obj, &path), "Failed to get key file path.");

	r = sc_lock(p15card->card);
	LOG_TEST_RET(p15card->card->ctx, r, "sc_lock() failed");

	do {
		if (path.len != 0 || path.aid.len != 0) {
			r = select_key_file(p15card, obj, senv);
			if (r < 0) {
				sc_log(p15card->card->ctx,
						"Unable to select private key file");
			}
		}
		if (r == SC_SUCCESS)
			r = sc_set_security_env(p15card->card, senv, 0);

		if (r == SC_SUCCESS)
			r = card_command(p15card->card, in, inlen, out, outlen);

		if (revalidated_cached_pin)
			/* only re-validate once */
			break;
		if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
			r = sc_pkcs15_pincache_revalidate(p15card, obj);
			if (r < 0)
				break;
			revalidated_cached_pin = 1;
		}
	} while (revalidated_cached_pin);

	sc_unlock(p15card->card);

	return r;
}

static int format_senv(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *obj,
		sc_security_env_t *senv_out, sc_algorithm_info_t **alg_info_out)
{
	sc_context_t *ctx = p15card->card->ctx;
	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
	const struct sc_pkcs15_skey_info *skey = (const struct sc_pkcs15_skey_info *) obj->data;

	memset(senv_out, 0, sizeof(*senv_out));

	/* Card driver should have the access to supported algorithms from 'tokenInfo'. So that
	 * it can get value of card specific 'AlgorithmInfo::algRef'. */
	memcpy(senv_out->supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv_out->supported_algos));

	if (!((obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY || (obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_SKEY))
		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This is not a private or secret key");

	/* If the key is not native, we can't operate with it. */
	if (!prkey->native)
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it");

	switch (obj->type) {
		case SC_PKCS15_TYPE_PRKEY_RSA:
			*alg_info_out = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
			if (*alg_info_out == NULL) {
				sc_log(ctx,
				       "Card does not support RSA with key length %"SC_FORMAT_LEN_SIZE_T"u",
				       prkey->modulus_length);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv_out->algorithm = SC_ALGORITHM_RSA;
			break;

		case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
			*alg_info_out = sc_card_find_gostr3410_alg(p15card->card, prkey->modulus_length);
			if (*alg_info_out == NULL) {
				sc_log(ctx,
				       "Card does not support GOSTR3410 with key length %"SC_FORMAT_LEN_SIZE_T"u",
				       prkey->modulus_length);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv_out->algorithm = SC_ALGORITHM_GOSTR3410;
			break;

		case SC_PKCS15_TYPE_PRKEY_EC:
			*alg_info_out = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL);
			if (*alg_info_out == NULL) {
				sc_log(ctx,
				       "Card does not support EC with field_size %"SC_FORMAT_LEN_SIZE_T"u",
				       prkey->field_length);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv_out->algorithm = SC_ALGORITHM_EC;

			senv_out->flags |= SC_SEC_ENV_ALG_REF_PRESENT;
			senv_out->algorithm_ref = prkey->field_length;
			break;
		case SC_PKCS15_TYPE_SKEY_GENERIC:
			if (obj->type == SC_PKCS15_TYPE_SKEY_GENERIC && skey->key_type != CKK_AES)
				LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported");
			*alg_info_out = sc_card_find_alg(p15card->card, SC_ALGORITHM_AES,
			skey->value_len, NULL);
			if (*alg_info_out == NULL) {
				sc_log(ctx,
				"Card does not support AES with key length %"SC_FORMAT_LEN_SIZE_T"u",
				skey->value_len);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv_out->algorithm = SC_ALGORITHM_AES;
			break;
			/* add other crypto types here */
		default:
			LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported");
	}
	senv_out->flags |= SC_SEC_ENV_ALG_PRESENT;

	/* optional keyReference attribute (the default value is -1) */
	if (prkey->key_reference >= 0) {
		senv_out->key_ref_len = 1;
		senv_out->key_ref[0] = prkey->key_reference & 0xFF;
		senv_out->flags |= SC_SEC_ENV_KEY_REF_PRESENT;
	}

	return SC_SUCCESS;
}

int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *obj,
		unsigned long flags,
		const u8 * in, size_t inlen, u8 *out, size_t outlen)
{
	sc_context_t *ctx = p15card->card->ctx;
	int r;
	sc_algorithm_info_t *alg_info = NULL;
	sc_security_env_t senv;
	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
	unsigned long pad_flags = 0, sec_flags = 0;

	LOG_FUNC_CALLED(ctx);

	if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP)))
		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for decryption");

	r = format_senv(p15card, obj, &senv, &alg_info);
	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
	senv.operation = SC_SEC_OPERATION_DECIPHER;

	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
	LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
	senv.algorithm_flags = sec_flags;

	r = use_key(p15card, obj, &senv, sc_decipher, in, inlen, out,
			outlen);
	LOG_TEST_RET(ctx, r, "use_key() failed");

	/* Strip any padding */
	if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
		size_t s = r;
		r = sc_pkcs1_strip_02_padding(ctx, out, s, out, &s);
		LOG_TEST_RET(ctx, r, "Invalid PKCS#1 padding");
	}

	LOG_FUNC_RETURN(ctx, r);
}

/* derive one key from another. RSA can use decipher, so this is for only ECDH
 * Since the value may be returned, and the call is expected to provide
 * the buffer, we used the PKCS#11 convention of outlen == 0 and out == NULL
 * to indicate that this is a request for the size.
 * In that case r = 0, and *poutlen = expected size
 */
int sc_pkcs15_derive(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *obj,
		unsigned long flags,
		const u8 * in, size_t inlen, u8 *out,
		size_t *poutlen)
{
	sc_context_t *ctx = p15card->card->ctx;
	int r;
	sc_algorithm_info_t *alg_info = NULL;
	sc_security_env_t senv;
	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
	unsigned long pad_flags = 0, sec_flags = 0;

	LOG_FUNC_CALLED(ctx);

	if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_DERIVE)))
		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for derivation");

	switch (obj->type) {
		case SC_PKCS15_TYPE_PRKEY_EC:
			if (out == NULL || *poutlen < (prkey->field_length + 7) / 8) {
				*poutlen = (prkey->field_length + 7) / 8;
				r = 0; /* say no data to return */
				LOG_FUNC_RETURN(ctx, r);
			}
			break;
		default:
			LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported");
	}

	r = format_senv(p15card, obj, &senv, &alg_info);
	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
	senv.operation = SC_SEC_OPERATION_DERIVE;

	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
	LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
	senv.algorithm_flags = sec_flags;

	r = use_key(p15card, obj, &senv, sc_decipher, in, inlen, out,
			*poutlen);
	LOG_TEST_RET(ctx, r, "use_key() failed");

	/* If card stores derived key on card, then no data is returned
	 * and the key must be used on the card. */
	*poutlen = r;
	LOG_FUNC_RETURN(ctx, r);
}

/*
 * Unwrap a key into a key object on card.
 * in holds the wrapped key data
 * the target file that target_key points to must be created before calling this function
 * Use pkcs15init to peform the complete unwrapping operation and create the pkcs#15 object for the new key.
 */
int sc_pkcs15_unwrap(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *key,
		struct sc_pkcs15_object *target_key,
		unsigned long flags,
		const u8 * in, size_t inlen,
		const u8 * param, size_t paramlen)
{
	sc_context_t *ctx = p15card->card->ctx;
	int r;
	sc_algorithm_info_t *alg_info = NULL;
	sc_security_env_t senv;
	const struct sc_pkcs15_prkey_info *src_prkey = (const struct sc_pkcs15_prkey_info *) key->data;
	const struct sc_pkcs15_skey_info *src_skey = (const struct sc_pkcs15_skey_info *) key->data;
	const struct sc_pkcs15_skey_info *tkey = (const struct sc_pkcs15_skey_info *) target_key->data;
	unsigned long pad_flags = 0, sec_flags = 0;
	u8 *out = 0;
	size_t poutlen = 0;
	sc_path_t path, target_file_id;
	sc_sec_env_param_t senv_param;

	LOG_FUNC_CALLED(ctx);

	if (key->type == SC_PKCS15_TYPE_PRKEY_RSA) {
		if (!(src_prkey->usage & (SC_PKCS15_PRKEY_USAGE_UNWRAP)))
			LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for unwrapping");
	}
	else if ((key->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_SKEY) {
		if (!(src_skey->usage & (SC_PKCS15_PRKEY_USAGE_UNWRAP)))
			LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for unwrapping");
	}
	else
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported");

	r = format_senv(p15card, key, &senv, &alg_info);
	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
	senv.operation = SC_SEC_OPERATION_UNWRAP;

	memset(&path, 0, sizeof(sc_path_t));
	memset(&target_file_id, 0, sizeof(sc_path_t));

	if (!tkey->path.len && tkey->path.aid.len) {
		/* Target key is a SDO allocated in application DF */
		target_file_id = tkey->path;
	}
	else if (tkey->path.len == 2 && p15card->file_app != NULL) {
		/* Path is relative to app. DF */
		path = p15card->file_app->path;
		target_file_id = tkey->path;
		sc_append_path(&path, &target_file_id);
		target_file_id = path;
	}
	else if (tkey->path.len > 2) {
		path = tkey->path;
		memcpy(target_file_id.value, tkey->path.value + tkey->path.len - 2, 2);
		target_file_id.len = 2;
		target_file_id.type = SC_PATH_TYPE_FILE_ID;
	}
	else {
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "invalid unwrapping target key path");
	}

	senv_param = (sc_sec_env_param_t) { SC_SEC_ENV_PARAM_TARGET_FILE, &target_file_id, sizeof(target_file_id)};
	LOG_TEST_RET(ctx, sec_env_add_param(&senv, &senv_param), "failed to add target file path to security environment");

	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
	LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
	senv.algorithm_flags = sec_flags;

	if ((sec_flags & (SC_ALGORITHM_AES_CBC | SC_ALGORITHM_AES_CBC_PAD)) > 0) {
	    senv_param = (sc_sec_env_param_t) { SC_SEC_ENV_PARAM_IV, (void*) param, paramlen };
	    LOG_TEST_RET(ctx, sec_env_add_param(&senv, &senv_param), "failed to add IV to security environment");
	}

	r = use_key(p15card, key, &senv, sc_unwrap, in, inlen, out,
		    poutlen);
	LOG_TEST_RET(ctx, r, "use_key() failed");

	LOG_FUNC_RETURN(ctx, r);
}

/*
 * Wrap a key and return a cryptogram
 * <key> is the wrapping key
 * <target_key> is the key to be wrapped
 * wrapped data is returned in <cryptogram>
 */
int sc_pkcs15_wrap(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *key,
		struct sc_pkcs15_object *target_key,
		unsigned long flags,
		u8 *cryptogram, size_t *crgram_len,
		const u8 *param, size_t paramlen) {
	sc_context_t *ctx = p15card->card->ctx;
	int r;
	sc_algorithm_info_t *alg_info = NULL;
	sc_security_env_t senv;
	const struct sc_pkcs15_prkey_info *src_prkey = (const struct sc_pkcs15_prkey_info *) key->data;
	const struct sc_pkcs15_skey_info *src_skey = (const struct sc_pkcs15_skey_info *) key->data;
	const struct sc_pkcs15_prkey_info *target_prkey = (const struct sc_pkcs15_prkey_info *) target_key->data;
	const struct sc_pkcs15_skey_info *target_skey = (const struct sc_pkcs15_skey_info *) target_key->data;
	unsigned long pad_flags = 0, sec_flags = 0;
	sc_path_t tkey_path;
	sc_path_t path, target_file_id;
	sc_sec_env_param_t senv_param;

	LOG_FUNC_CALLED(ctx);

	switch (key->type) {
		case SC_PKCS15_TYPE_PRKEY_RSA:
			if (!(src_prkey->usage & (SC_PKCS15_PRKEY_USAGE_WRAP)))
				LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for wrapping");
			break;
		case SC_PKCS15_TYPE_SKEY_DES:
		case SC_PKCS15_TYPE_SKEY_3DES:
		case SC_PKCS15_TYPE_SKEY_GENERIC:
			if (!(src_skey->usage & (SC_PKCS15_PRKEY_USAGE_WRAP)))
			LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for wrapping");
			break;
		default:
			LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Wrapping key type not supported");
	}

	if (!(target_key->type == SC_PKCS15_TYPE_PRKEY_RSA ||
			(target_key->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_SKEY)) {
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Target key type not supported");
	}

	r = format_senv(p15card, key, &senv, &alg_info);
	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
	senv.operation = SC_SEC_OPERATION_WRAP;

	memset(&path, 0, sizeof (sc_path_t));
	memset(&target_file_id, 0, sizeof (sc_path_t));

	switch (target_key->type) {
		case SC_PKCS15_TYPE_PRKEY_RSA:
			tkey_path = target_prkey->path;
			break;
		default: /* we already know it is a secret key */
			tkey_path = target_skey->path;
			break;
	}

	if (!tkey_path.len && tkey_path.aid.len) {
		/* Target key is a SDO allocated in application DF */
		target_file_id = tkey_path;
	} else if (tkey_path.len == 2 && p15card->file_app != NULL) {
		/* Path is relative to app. DF */
		path = p15card->file_app->path;
		target_file_id = tkey_path;
		sc_append_path(&path, &target_file_id);
		target_file_id  = path;
	} else if (tkey_path.len > 2) {
		/*path = tkey_path;*/
		memcpy(target_file_id.value, tkey_path.value + tkey_path.len - 2, 2);
		target_file_id.len = 2;
		target_file_id.type = SC_PATH_TYPE_FILE_ID;
	}
	else {
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "invalid unwrapping target key path");
	}
	senv_param = (sc_sec_env_param_t) { SC_SEC_ENV_PARAM_TARGET_FILE, &target_file_id, sizeof(target_file_id)};
	LOG_TEST_RET(ctx, sec_env_add_param(&senv, &senv_param), "failed to add target file path to security environment");

	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
	LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
	senv.algorithm_flags = sec_flags;

	if ((sec_flags & (SC_ALGORITHM_AES_CBC | SC_ALGORITHM_AES_CBC_PAD)) > 0) {
		senv_param = (sc_sec_env_param_t) { SC_SEC_ENV_PARAM_IV, (void*) param, paramlen };
		LOG_TEST_RET(ctx, sec_env_add_param(&senv, &senv_param), "failed to add IV to security environment");
	}

	r = use_key(p15card, key, &senv, sc_wrap, NULL, 0, cryptogram, crgram_len ? *crgram_len : 0);

	if (r > -1 && crgram_len) {
		if (*crgram_len < (size_t) r) {
			*crgram_len = r;
			if (cryptogram != NULL) /* if NULL, return success and required buffer length by PKCS#11 convention */
				LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Buffer too small to hold the wrapped key.");
		}
		*crgram_len = r;
	}

	LOG_FUNC_RETURN(ctx, r);
}


/* copied from pkcs15-cardos.c */
#define USAGE_ANY_SIGN          (SC_PKCS15_PRKEY_USAGE_SIGN|\
                                 SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)
#define USAGE_ANY_DECIPHER      (SC_PKCS15_PRKEY_USAGE_DECRYPT|\
                                 SC_PKCS15_PRKEY_USAGE_UNWRAP)

int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
				const struct sc_pkcs15_object *obj,
				unsigned long flags, const u8 *in, size_t inlen,
				u8 *out, size_t outlen)
{
	sc_context_t *ctx = p15card->card->ctx;
	int r;
	sc_security_env_t senv;
	sc_algorithm_info_t *alg_info;
	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
	u8 buf[1024], *tmp;
	size_t modlen;
	unsigned long pad_flags = 0, sec_flags = 0;

	LOG_FUNC_CALLED(ctx);

	if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER|
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)))
		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for signing");

	r = format_senv(p15card, obj, &senv, &alg_info);
	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
	senv.operation = SC_SEC_OPERATION_SIGN;

	switch (obj->type) {
		case SC_PKCS15_TYPE_PRKEY_RSA:
			modlen = (prkey->modulus_length + 7) / 8;
			break;
		case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
			modlen = (prkey->modulus_length + 7) / 8 * 2;
			break;
		case SC_PKCS15_TYPE_PRKEY_EC:
			modlen = ((prkey->field_length +7) / 8) * 2;  /* 2*nLen */ 
			break;
		default:
			LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported");
	}

	/* Probably never happens, but better make sure */
	if (inlen > sizeof(buf) || outlen < modlen)
		LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL);

	memcpy(buf, in, inlen);

	/* revert data to sign when signing with the GOST key.
	 * TODO: can it be confirmed by the GOST standard?
	 * TODO: tested with RuTokenECP, has to be validated for RuToken. */
	if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) {
		r = sc_mem_reverse(buf, inlen);
		LOG_TEST_RET(ctx, r, "Reverse memory error");
	}

	tmp = buf;

	/* flags: the requested algo
	 * algo_info->flags: what is supported by the card
	 * senv.algorithm_flags: what the card will have to do */

	/* if the card has SC_ALGORITHM_NEED_USAGE set, and the
	 * key is for signing and decryption, we need to emulate signing */
	/* TODO: -DEE assume only RSA keys will ever use _NEED_USAGE */

	sc_log(ctx, "supported algorithm flags 0x%X, private key usage 0x%X", alg_info->flags, prkey->usage);
	if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) &&
		((prkey->usage & USAGE_ANY_SIGN) &&
		(prkey->usage & USAGE_ANY_DECIPHER)) ) {
		size_t tmplen = sizeof(buf);
		if (flags & SC_ALGORITHM_RSA_RAW) {
			r = sc_pkcs15_decipher(p15card, obj, flags, in, inlen, out, outlen);
			LOG_FUNC_RETURN(ctx, r);
		}
		if (modlen > tmplen)
			LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!");

		/* XXX Assuming RSA key here */
		r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length);

		/* no padding needed - already done */
		flags &= ~SC_ALGORITHM_RSA_PADS;
		/* instead use raw rsa */
		flags |= SC_ALGORITHM_RSA_RAW;

		LOG_TEST_RET(ctx, r, "Unable to add padding");

		r = sc_pkcs15_decipher(p15card, obj, flags, buf, modlen, out, outlen);
		LOG_FUNC_RETURN(ctx, r);
	}


	/* If the card doesn't support the requested algorithm, we normally add the
	 * padding here in software and ask the card to do a raw signature.  There's
	 * one exception to that, where we might be able to get the signature to
	 * succeed by stripping padding if the card only offers higher-level
	 * signature operations.  The only thing we can strip is the DigestInfo
	 * block from PKCS1 padding. */
	if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
	    !(alg_info->flags & SC_ALGORITHM_RSA_RAW) &&
	    !(alg_info->flags & SC_ALGORITHM_RSA_HASH_NONE) &&
	    (alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
		unsigned int algo;
		size_t tmplen = sizeof(buf);

		r = sc_pkcs1_strip_digest_info_prefix(&algo, tmp, inlen, tmp, &tmplen);
		if (r != SC_SUCCESS || algo == SC_ALGORITHM_RSA_HASH_NONE) {
			sc_mem_clear(buf, sizeof(buf));
			LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
		}
		flags &= ~SC_ALGORITHM_RSA_HASH_NONE;
		flags |= algo;
		inlen = tmplen;
	}

	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
	if (r != SC_SUCCESS) {
		sc_mem_clear(buf, sizeof(buf));
		LOG_FUNC_RETURN(ctx, r);
	}
	senv.algorithm_flags = sec_flags;

	sc_log(ctx, "DEE flags:0x%8.8lx alg_info->flags:0x%8.8x pad:0x%8.8lx sec:0x%8.8lx",
		flags, alg_info->flags, pad_flags, sec_flags);

	/* add the padding bytes (if necessary) */
	if (pad_flags != 0) {
		size_t tmplen = sizeof(buf);

		/* XXX Assuming RSA key here */
		r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen,
		    prkey->modulus_length);
		LOG_TEST_RET(ctx, r, "Unable to add padding");
		inlen = tmplen;
	}
	else if ( senv.algorithm == SC_ALGORITHM_RSA &&
	          (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) {
		/* Add zero-padding if input is shorter than the modulus */
		if (inlen < modlen) {
			if (modlen > sizeof(buf))
				return SC_ERROR_BUFFER_TOO_SMALL;
			memmove(tmp+modlen-inlen, tmp, inlen);
			memset(tmp, 0, modlen-inlen);
		}
		inlen = modlen;
	}
	/* PKCS#11 MECHANISMS V2.30: 6.3.1 EC Signatures
	 * If the length of the hash value is larger than the bit length of n, only
	 * the leftmost bits of the hash up to the length of n will be used. Any
	 * truncation is done by the token.
	 */
	else if (senv.algorithm == SC_ALGORITHM_EC &&
			(flags & SC_ALGORITHM_ECDSA_HASH_NONE) != 0) {
		inlen = MIN(inlen, (prkey->field_length+7)/8);
	}


	r = use_key(p15card, obj, &senv, sc_compute_signature, tmp, inlen,
			out, outlen);
	LOG_TEST_RET(ctx, r, "use_key() failed");

	/* Some cards may return RSA signature as integer without leading zero bytes */
	/* Already know outlen >= modlen and r >= 0 */
	if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA && (unsigned)r < modlen) {
		memmove(out + modlen - r, out, r);
		memset(out, 0, modlen - r);
		r = modlen;
	}

	sc_mem_clear(buf, sizeof(buf));

	LOG_FUNC_RETURN(ctx, r);
}