LIBOPENSC_API 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; 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); 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 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_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP))) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for decryption"); switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_RSA: 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.algorithm = SC_ALGORITHM_RSA; break; case SC_PKCS15_TYPE_PRKEY_GOSTR3410: 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.algorithm = SC_ALGORITHM_GOSTR3410; break; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported"); } 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; senv.operation = SC_SEC_OPERATION_DECIPHER; 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); LOG_TEST_RET(ctx, r, "sc_lock() failed"); 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_decipher(p15card->card, in, inlen, out, outlen); if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS) r = sc_decipher(p15card->card, in, inlen, out, outlen); } sc_unlock(p15card->card); LOG_TEST_RET(ctx, r, "sc_decipher() failed"); /* Strip any padding */ if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { size_t s = r; r = sc_pkcs1_strip_02_padding(out, s, out, &s); LOG_TEST_RET(ctx, r, "Invalid PKCS#1 padding"); } LOG_FUNC_RETURN(ctx, r); }
static int do_pkdecrypt(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 char *s; if (argc != 2) 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; } /* setup the security environment */ memset (&senv, 0, sizeof senv); senv.operation = SC_SEC_OPERATION_DECIPHER; 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 decryption */ /* FIXME: It is pretty useless to to this test padding :-; */ memmove(indata+(sizeof indata - indatalen), indata, indatalen); memset(indata, 0, (sizeof indata - indatalen)); indatalen = sizeof indata; r = sc_decipher(card, indata, indatalen, outdata, outdatalen); if (r<0) { printf("Decryption failed: %s\n", sc_strerror (r)); return -1; } hex_dump_asc (stdout, outdata, r, -1); printf("Done.\n"); return 0; usage: printf("Usage: pkdecrypt <key ref> <data>\n"); return -1; #endif }
/* 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 */ LIBOPENSC_API 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, unsigned long *poutlen) { sc_context_t *ctx = p15card->card->ctx; int r; sc_algorithm_info_t *alg_info; 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); 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 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_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: 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); } if (out == NULL || *poutlen < (prkey->field_length +7) / 8) { *poutlen = (prkey->field_length +7) / 8; r = 0; /* say no data to return */ goto out; } 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; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported"); } 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; senv.operation = SC_SEC_OPERATION_DERIVE; /* 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"); 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"); } /* TODO Do we need a sc_derive? PIV at least can use the decipher, * senv.operation = SC_SEC_OPERATION_DERIVE; */ r = sc_decipher(p15card->card, in, inlen, out, *poutlen); if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS) r = sc_decipher(p15card->card, in, inlen, out, *poutlen); } sc_unlock(p15card->card); LOG_TEST_RET(ctx, r, "sc_decipher/derive() failed"); /* Strip any padding */ if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { size_t s = r; r = sc_pkcs1_strip_02_padding(out, s, out, &s); LOG_TEST_RET(ctx, r, "Invalid PKCS#1 padding"); } /* If card stores derived key on card, then no data is returned * and the key must be used on the card. */ *poutlen = r; out: LOG_FUNC_RETURN(ctx, r); }
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) { int r; sc_algorithm_info_t *alg_info; sc_security_env_t senv; sc_context_t *ctx = p15card->card->ctx; const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data; unsigned long pad_flags = 0, sec_flags = 0; SC_FUNC_CALLED(ctx, 1); /* 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_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP))) { sc_error(ctx, "This key cannot be used for decryption\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; r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags); if (r != SC_SUCCESS) return r; senv.algorithm_flags = sec_flags; senv.operation = SC_SEC_OPERATION_DECIPHER; 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_decipher(p15card->card, in, inlen, out, outlen); sc_unlock(p15card->card); SC_TEST_RET(ctx, r, "sc_decipher() failed"); /* Strip any padding */ if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { r = sc_pkcs1_strip_02_padding(out, (size_t)r, out, (size_t *) &r); SC_TEST_RET(ctx, r, "Invalid PKCS#1 padding"); } return r; }