2001-11-20 22:21:58 +00:00
|
|
|
|
/*
|
2002-01-10 12:33:56 +00:00
|
|
|
|
* pkcs15-sec.c: PKCS#15 cryptography functions
|
2001-11-20 22:21:58 +00:00
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2001 Juha Yrj<EFBFBD>l<EFBFBD> <juha.yrjola@iki.fi>
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2001-12-25 20:45:48 +00:00
|
|
|
|
#include "sc-internal.h"
|
2001-11-24 13:32:52 +00:00
|
|
|
|
#include "opensc-pkcs15.h"
|
2001-12-20 12:22:18 +00:00
|
|
|
|
#include "sc-log.h"
|
2001-11-20 22:21:58 +00:00
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
2001-12-15 01:29:51 +00:00
|
|
|
|
#include <unistd.h>
|
2001-11-20 22:21:58 +00:00
|
|
|
|
|
|
|
|
|
int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
|
|
|
|
const struct sc_pkcs15_prkey_info *prkey,
|
2002-01-20 21:20:09 +00:00
|
|
|
|
const u8 * in, size_t inlen, u8 *out, size_t outlen)
|
2001-11-20 22:21:58 +00:00
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
struct sc_security_env senv;
|
2001-12-20 12:22:18 +00:00
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
struct sc_path path, file_id;
|
|
|
|
|
|
|
|
|
|
if (prkey->path.len < 2)
|
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
if (prkey->path.len == 2) {
|
2002-02-20 09:56:47 +00:00
|
|
|
|
path = p15card->file_app->path;
|
|
|
|
|
sc_append_path(&path, &prkey->path);
|
2002-01-20 21:20:09 +00:00
|
|
|
|
file_id = prkey->path;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
} else { /* path.len > 2 */
|
2002-01-20 21:20:09 +00:00
|
|
|
|
path = prkey->path;
|
|
|
|
|
memcpy(file_id.value, prkey->path.value + prkey->path.len - 2, 2);
|
|
|
|
|
file_id.len = 2;
|
|
|
|
|
}
|
|
|
|
|
senv.algorithm = SC_ALGORITHM_RSA;
|
|
|
|
|
senv.algorithm_flags = SC_ALGORITHM_RSA_PKCS1_PAD;
|
|
|
|
|
|
|
|
|
|
senv.file_ref = file_id;
|
2001-12-25 20:45:48 +00:00
|
|
|
|
senv.operation = SC_SEC_OPERATION_DECIPHER;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
senv.key_ref_len = 1;
|
|
|
|
|
senv.key_ref[0] = prkey->key_reference & 0xFF;
|
|
|
|
|
senv.flags = SC_SEC_ENV_KEY_REF_PRESENT | SC_SEC_ENV_FILE_REF_PRESENT;
|
|
|
|
|
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
|
|
|
|
|
|
2001-12-21 23:34:47 +00:00
|
|
|
|
SC_FUNC_CALLED(ctx, 1);
|
2002-01-20 21:20:09 +00:00
|
|
|
|
r = sc_select_file(p15card->card, &path, NULL);
|
2001-12-20 13:57:58 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_select_file() failed");
|
2001-12-22 20:43:09 +00:00
|
|
|
|
#if 0
|
|
|
|
|
/* FIXME! */
|
2001-11-20 22:21:58 +00:00
|
|
|
|
r = sc_restore_security_env(p15card->card, 0); /* empty SE */
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_restore_security_env() failed");
|
2001-12-22 20:43:09 +00:00
|
|
|
|
#endif
|
2002-01-16 23:59:18 +00:00
|
|
|
|
r = sc_set_security_env(p15card->card, &senv, 0);
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_set_security_env() failed");
|
2001-11-20 22:21:58 +00:00
|
|
|
|
r = sc_decipher(p15card->card, in, inlen, out, outlen);
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_decipher() failed");
|
2001-11-21 21:19:58 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-20 21:20:09 +00:00
|
|
|
|
static int pkcs1_add_padding(const u8 *in, size_t inlen, u8 *out, size_t outlen)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2002-02-25 18:47:42 +00:00
|
|
|
|
if (inlen + 11 > outlen)
|
2002-01-20 21:20:09 +00:00
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
*out++ = 0x00;
|
|
|
|
|
*out++ = 0x01;
|
|
|
|
|
|
|
|
|
|
i = outlen - 3 - inlen;
|
|
|
|
|
memset(out, 0xFF, i);
|
|
|
|
|
out += i;
|
|
|
|
|
*out++ = 0x00;
|
|
|
|
|
memcpy(out, in, inlen);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-21 21:19:58 +00:00
|
|
|
|
int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
|
|
|
|
const struct sc_pkcs15_prkey_info *prkey,
|
2002-02-26 11:23:25 +00:00
|
|
|
|
unsigned int flags, const u8 *in, size_t inlen,
|
2002-01-20 21:20:09 +00:00
|
|
|
|
u8 *out, size_t outlen)
|
2001-11-21 21:19:58 +00:00
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
struct sc_security_env senv;
|
2001-12-20 12:22:18 +00:00
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
u8 buf[256];
|
|
|
|
|
struct sc_path path, file_id;
|
|
|
|
|
|
|
|
|
|
if (prkey->path.len < 2)
|
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
if (prkey->path.len == 2) {
|
2002-02-20 09:56:47 +00:00
|
|
|
|
path = p15card->file_app->path;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
memcpy(path.value + path.len, prkey->path.value, prkey->path.len);
|
|
|
|
|
path.len += prkey->path.len;
|
|
|
|
|
file_id = prkey->path;
|
|
|
|
|
} else {
|
|
|
|
|
path = prkey->path;
|
|
|
|
|
memcpy(file_id.value, prkey->path.value + prkey->path.len - 2, 2);
|
|
|
|
|
file_id.len = 2;
|
2001-11-21 21:19:58 +00:00
|
|
|
|
}
|
2002-01-20 21:20:09 +00:00
|
|
|
|
senv.algorithm = SC_ALGORITHM_RSA;
|
|
|
|
|
senv.algorithm_flags = SC_ALGORITHM_RSA_PKCS1_PAD;
|
2002-03-01 11:52:55 +00:00
|
|
|
|
#if 0
|
2002-02-26 11:23:25 +00:00
|
|
|
|
if (flags & SC_PKCS15_HASH_SHA1)
|
2002-01-20 21:20:09 +00:00
|
|
|
|
senv.algorithm_flags |= SC_ALGORITHM_RSA_HASH_SHA1;
|
2002-03-01 11:52:55 +00:00
|
|
|
|
#endif
|
2002-02-26 11:23:25 +00:00
|
|
|
|
if (flags & SC_PKCS15_PAD_PKCS1_V1_5) {
|
2002-01-20 21:20:09 +00:00
|
|
|
|
size_t modlen = prkey->modulus_length >> 3;
|
|
|
|
|
|
|
|
|
|
if (inlen > (modlen - 11)) {
|
|
|
|
|
error(ctx, "Input data length too large.\n");
|
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
}
|
|
|
|
|
if (modlen > sizeof(buf)) {
|
|
|
|
|
error(ctx, "Too large modulus.\n");
|
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
}
|
|
|
|
|
r = pkcs1_add_padding(in, inlen, buf, modlen);
|
|
|
|
|
SC_TEST_RET(p15card->card->ctx, r, "Error adding PKCS #1 padding");
|
|
|
|
|
in = buf;
|
|
|
|
|
inlen = modlen;
|
|
|
|
|
}
|
|
|
|
|
senv.file_ref = file_id;
|
2001-12-25 20:45:48 +00:00
|
|
|
|
senv.operation = SC_SEC_OPERATION_SIGN;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
senv.key_ref_len = 1;
|
|
|
|
|
senv.key_ref[0] = prkey->key_reference & 0xFF;
|
|
|
|
|
senv.flags = SC_SEC_ENV_KEY_REF_PRESENT | SC_SEC_ENV_FILE_REF_PRESENT;
|
|
|
|
|
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
|
2001-12-21 23:34:47 +00:00
|
|
|
|
SC_FUNC_CALLED(ctx, 1);
|
2002-01-20 21:20:09 +00:00
|
|
|
|
r = sc_select_file(p15card->card, &path, NULL);
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_select_file() failed");
|
2001-12-22 20:43:09 +00:00
|
|
|
|
#if 0
|
|
|
|
|
/* FIXME! */
|
2001-11-21 21:19:58 +00:00
|
|
|
|
r = sc_restore_security_env(p15card->card, 0); /* empty SE */
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_restore_security_env() failed");
|
2001-12-22 20:43:09 +00:00
|
|
|
|
#endif
|
2002-01-16 23:59:18 +00:00
|
|
|
|
r = sc_set_security_env(p15card->card, &senv, 0);
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_set_security_env() failed");
|
2001-11-21 21:19:58 +00:00
|
|
|
|
r = sc_compute_signature(p15card->card, in, inlen, out, outlen);
|
2001-12-20 12:22:18 +00:00
|
|
|
|
SC_TEST_RET(ctx, r, "sc_compute_signature() failed");
|
2001-11-21 21:19:58 +00:00
|
|
|
|
|
|
|
|
|
return r;
|
2001-11-20 22:21:58 +00:00
|
|
|
|
}
|