Example #1
0
static int rutoken_mac(sc_card_t *card, u8 keyid,
		const u8 *in, size_t inlen,
		u8 *out, size_t outlen)
{
	int r;
	sc_security_env_t env;

	memset(&env, 0, sizeof(env));
	env.key_ref[0] = keyid;
	env.key_ref_len = 1;
	env.algorithm = SC_ALGORITHM_GOST;
	env.operation = SC_SEC_OPERATION_SIGN;

	/*  set security env  */
	r = sc_set_security_env(card, &env, 0);
	if (r) {
		fprintf(stderr, "Error: Computation signature (MAC) failed"
				" (set security environment): %s\n", sc_strerror(r));
		return -1;
	}
	/*  calculate hash  */
	r = sc_compute_signature(card, in, inlen, out, outlen);
	if (r) {
		fprintf(stderr, "Error: Computation signature (MAC) failed: %s\n",
				sc_strerror(r));
		return -1;
	}
	return 0;
}
Example #2
0
LIBOPENSC_API 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);
	sc_log(ctx, "security operation flags 0x%X", flags);

	memset(&senv, 0, sizeof(senv));

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

	if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY)
		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This is not a private 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");

	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");

	switch (obj->type) {
		case SC_PKCS15_TYPE_PRKEY_RSA:
			modlen = prkey->modulus_length / 8;
			alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
			if (alg_info == NULL) {
				sc_log(ctx, "Card does not support RSA with key length %d", prkey->modulus_length);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv.flags |= SC_SEC_ENV_ALG_PRESENT;
			senv.algorithm = SC_ALGORITHM_RSA;
			break;

		case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
			modlen = (prkey->modulus_length + 7) / 8 * 2;
			alg_info = sc_card_find_gostr3410_alg(p15card->card, prkey->modulus_length);
			if (alg_info == NULL) {
				sc_log(ctx, "Card does not support GOSTR3410 with key length %d", prkey->modulus_length);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv.flags |= SC_SEC_ENV_ALG_PRESENT;
			senv.algorithm = SC_ALGORITHM_GOSTR3410;
			break;

		case SC_PKCS15_TYPE_PRKEY_EC:
			modlen = ((prkey->field_length +7) / 8) * 2;  /* 2*nLen */ 
			alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length);
			if (alg_info == NULL) {
				sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length);
				LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
			}
			senv.algorithm = SC_ALGORITHM_EC;
			senv.flags |= SC_SEC_ENV_ALG_PRESENT;

			senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
			senv.algorithm_ref = prkey->field_length;
			break;
			/* add other crypto types here */
		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)
		sc_mem_reverse(buf, inlen);

	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!");

		r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, modlen);

		/* 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, see if we
	 * can strip the input so a more restrictive algo can be used */
	if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
	    !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) {
		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.8x alg_info->flags:0x%8.8x pad:0x%8.8x sec:0x%8.8x",
		flags, alg_info->flags, pad_flags, sec_flags);

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

		r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen);
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, 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;
	}

	senv.operation = SC_SEC_OPERATION_SIGN;

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

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

	sc_log(ctx, "Private key path '%s'", sc_print_path(&prkey->path));
	if (prkey->path.len != 0 || prkey->path.aid.len != 0) {
		r = select_key_file(p15card, prkey, &senv);
		if (r < 0) {
			sc_unlock(p15card->card);
			LOG_TEST_RET(ctx, r,"Unable to select private key file");
		}
	}

	r = sc_set_security_env(p15card->card, &senv, 0);
	if (r < 0) {
		sc_unlock(p15card->card);
		LOG_TEST_RET(ctx, r, "sc_set_security_env() failed");
	}

	r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen);
	if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
		if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS)
			r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen);

	sc_mem_clear(buf, sizeof(buf));
	sc_unlock(p15card->card);
	LOG_TEST_RET(ctx, r, "sc_compute_signature() failed");

	LOG_FUNC_RETURN(ctx, r);
}
static int do_pksign(int argc, char **argv)
{
	puts ("Not yet supported");
	return -1;
#if 0
	int i, ref, r;
	u8 indata[128];
	size_t indatalen = sizeof indata;
	u8 outdata[128];
	size_t outdatalen = sizeof outdata;
	sc_security_env_t senv;
	const u8 *oid;
	int oidlen;
	const char *s;

	if (argc < 2 || argc > 3)
		goto usage;
	if (sscanf (argv[0], "%d", &ref) != 1 || ref < 0 || ref > 255) {
		printf("Invalid key reference.\n");
		goto usage;
	}

	if (argv[1][0] == '"') {
		for (s = argv[1]+1, i = 0;
		     i < sizeof indata && *s && *s != '"'; i++) 
			indata[i] = *s++;
		indatalen = i;
	} else if (sc_hex_to_bin(argv[1], indata, &indatalen)) {
		printf("Invalid data value.\n");
		goto usage;
	}

		
	if (argc == 3) {
		if (!strcasecmp(argv[2], "SHA1")) {
			oid = oid_sha1; oidlen = sizeof oid_sha1;
		}
		else if (!strcasecmp (argv[2], "MD5")) {
			oid = oid_md5; oidlen = sizeof oid_md5;
		}
		else if (!strcasecmp (argv[2], "RMD160")) {
			oid = oid_rmd160; oidlen = sizeof oid_rmd160;
		}
		else {
			goto usage;
		}
	 }
	else {
		oid = ""; oidlen = 0;
	}
	
	if (indatalen + oidlen > sizeof indata) {
		printf("Data value to long.\n");
		goto usage;
	}
	
	memmove(indata + oidlen, indata, indatalen);
	memcpy(indata, oid, oidlen);
	indatalen += oidlen;

	/* setup the security environment */
	/* FIXME The values won't work for other cards.  They do work
	   for TCOS because there is no need for a security
	   environment there */
	memset(&senv, 0, sizeof senv);
	senv.operation = SC_SEC_OPERATION_SIGN;
	senv.algorithm = SC_ALGORITHM_RSA;
	senv.key_ref_len = 1;
	senv.key_ref[0] = ref;
 	senv.flags = (SC_SEC_ENV_KEY_REF_PRESENT | SC_SEC_ENV_ALG_PRESENT);
	r = sc_set_security_env(card, &senv, 0);
	if (r) {
		printf("Failed to set the security environment: %s\n",
		       sc_strerror (r));
		return -1;
	}

	/* Perform the actual sign. */ 
	r = sc_compute_signature(card, indata, indatalen,
	                         outdata, outdatalen);
	if (r<0) {
		printf("Signing failed: %s\n",  sc_strerror (r));
		return -1;
	}
	hex_dump_asc(stdout, outdata, r, -1);
	printf ("Done.\n");
	return 0;
usage:
	printf ("Usage: pksign <key ref> <data> [MD5|SHA1|RMD160]\n");
	return -1;
#endif
}
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)
{
    int r;
    sc_security_env_t senv;
    sc_context_t *ctx = p15card->card->ctx;
    sc_algorithm_info_t *alg_info;
    const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
    u8 buf[512], *tmp;
    size_t modlen = prkey->modulus_length / 8;
    unsigned long pad_flags = 0, sec_flags = 0;

    SC_FUNC_CALLED(ctx, 1);

    /* some strange cards/setups need decrypt to sign ... */
    if (p15card->flags & SC_PKCS15_CARD_FLAG_SIGN_WITH_DECRYPT) {
        size_t tmplen = sizeof(buf);
        if (flags & SC_ALGORITHM_RSA_RAW) {
            return sc_pkcs15_decipher(p15card, obj,flags,
                                      in, inlen, out, outlen);
        }
        if (modlen > tmplen) {
            sc_error(ctx, "Buffer too small, needs recompile!\n");
            return SC_ERROR_NOT_ALLOWED;
        }
        r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, modlen);

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

        SC_TEST_RET(ctx, r, "Unable to add padding");
        r = sc_pkcs15_decipher(p15card, obj,flags, buf, modlen,
                               out, outlen);
        return r;
    }

    /* If the key is extractable, the caller should extract the
     * key and do the crypto himself */
    if (!prkey->native)
        return SC_ERROR_EXTRACTABLE_KEY;

    if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER|
                          SC_PKCS15_PRKEY_USAGE_NONREPUDIATION))) {
        sc_error(ctx, "This key cannot be used for signing\n");
        return SC_ERROR_NOT_ALLOWED;
    }

    alg_info = _sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
    if (alg_info == NULL) {
        sc_error(ctx, "Card does not support RSA with key length %d\n", prkey->modulus_length);
        return SC_ERROR_NOT_SUPPORTED;
    }
    senv.algorithm = SC_ALGORITHM_RSA;

    /* Probably never happens, but better make sure */
    if (inlen > sizeof(buf) || outlen < modlen)
        return SC_ERROR_BUFFER_TOO_SMALL;
    memcpy(buf, in, inlen);
    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 doesn't support the requested algorithm, see if we
     * can strip the input so a more restrictive algo can be used */
    if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
            !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) {
        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));
            return 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));
        return r;
    }
    senv.algorithm_flags = sec_flags;

    /* add the padding bytes (if necessary) */
    if (pad_flags != 0) {
        size_t tmplen = sizeof(buf);
        r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen);
        SC_TEST_RET(ctx, r, "Unable to add padding");
        inlen = tmplen;
    } else if ((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);
        }
    }

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

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

    if (prkey->path.len != 0) {
        r = select_key_file(p15card, prkey, &senv);
        if (r < 0) {
            sc_unlock(p15card->card);
            SC_TEST_RET(ctx,r,"Unable to select private key file");
        }
    }

    r = sc_set_security_env(p15card->card, &senv, 0);
    if (r < 0) {
        sc_unlock(p15card->card);
        SC_TEST_RET(ctx, r, "sc_set_security_env() failed");
    }

    r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen);
    sc_mem_clear(buf, sizeof(buf));
    sc_unlock(p15card->card);
    SC_TEST_RET(ctx, r, "sc_compute_signature() failed");

    return r;
}