opensc/src/sslengines/engine_opensc.c

355 lines
8.9 KiB
C

/*
* Copyright (c) 2002 Juha Yrjölä. All rights reserved.
* Copyright (c) 2001 Markus Friedl.
* Copyright (c) 2003 Kevin Stefanik
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/objects.h>
#include <opensc/opensc.h>
#include <opensc/pkcs15.h>
#include "engine_opensc.h"
/* static state info one card/reader at a time */
static int quiet = 1;
static int sc_reader_id = 0;
static sc_context_t *ctx = NULL;
static sc_card_t *card = NULL;
static sc_pkcs15_card_t *p15card = NULL;
static char *sc_pin = NULL;
int opensc_finish(void)
{
if (p15card) {
sc_pkcs15_unbind(p15card);
p15card = NULL;
}
if (card) {
sc_disconnect_card(card, 0);
card = NULL;
}
if (ctx) {
sc_release_context(ctx);
ctx = NULL;
}
return 1;
}
int opensc_init(void)
{
int r = 0;
if (!quiet)
fprintf(stderr, "initializing engine");
r = sc_establish_context(&ctx, "openssl");
if (r)
goto err;
r = sc_connect_card(ctx->reader[sc_reader_id], 0, &card);
if (r)
goto err;
r = sc_pkcs15_bind(card, &p15card);
if (r)
goto err;
return 1;
err:
/* need to do engine stuff? */
fprintf(stderr, "error: %d", r);
opensc_finish();
return 0;
}
int opensc_rsa_finish(RSA * rsa)
{
struct sc_pkcs15_key_id *key_id;
key_id = (struct sc_pkcs15_key_id *) RSA_get_app_data(rsa);
free(key_id);
if (sc_pin) {
free(sc_pin);
}
return 1;
}
BIGNUM *sc_bignum_t_to_BIGNUM(sc_pkcs15_bignum_t * bignum, BIGNUM * BN)
{
BN_bin2bn((unsigned char *) bignum->data, bignum->len, BN);
return BN;
}
void sc_set_pubkey_data(EVP_PKEY * key_out, sc_pkcs15_pubkey_t * pubkey)
{
key_out->pkey.rsa->n =
sc_bignum_t_to_BIGNUM(&(pubkey->u.rsa.modulus), BN_new());
key_out->pkey.rsa->e =
sc_bignum_t_to_BIGNUM(&(pubkey->u.rsa.exponent), BN_new());
}
/* private key operations */
#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \
SC_PKCS15_PRKEY_USAGE_UNWRAP
#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
int sc_prkey_op_init(const RSA * rsa, struct sc_pkcs15_object **key_obj_out,
unsigned int usage)
{
int r;
struct sc_pkcs15_object *key_obj;
struct sc_pkcs15_prkey_info *key;
struct sc_pkcs15_id *key_id;
struct sc_pkcs15_object *pin_obj;
struct sc_pkcs15_pin_info *pin;
key_id = (struct sc_pkcs15_id *) RSA_get_app_data(rsa);
if (key_id == NULL) {
fprintf(stderr, "key not loaded yet");
return -1;
}
if (p15card == NULL) {
opensc_finish();
r = opensc_init();
if (r) {
fprintf(stderr, "SmartCard init failed: %s", sc_strerror(r));
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id_usage(p15card, key_id, usage, &key_obj);
if (r) {
fprintf(stderr, "Unable to find private key from SmartCard: %s",
sc_strerror(r));
goto err;
}
key = (struct sc_pkcs15_prkey_info *) key_obj->data;
r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id, &pin_obj);
if (r) {
fprintf(stderr, "Unable to find PIN object from SmartCard: %s",
sc_strerror(r));
goto err;
}
pin = (struct sc_pkcs15_pin_info *) pin_obj->data;
r = sc_lock(card);
if (r) {
fprintf(stderr, "Unable to lock smartcard: %s", sc_strerror(r));
goto err;
}
if (sc_pin != NULL) {
r = sc_pkcs15_verify_pin(p15card, pin, (const u8 *) sc_pin,
strlen(sc_pin));
if (r) {
sc_unlock(card);
fprintf(stderr, "PIN code verification failed: %s",
sc_strerror(r));
goto err;
}
} else {
fprintf(stderr, "Warning: PIN not verified");
}
*key_obj_out = key_obj;
return 0;
err:
return -1;
}
EVP_PKEY *opensc_load_public_key(ENGINE * e, const char *s_key_id,
UI_METHOD * ui_method, void *callback_data)
{
int r;
struct sc_pkcs15_id *id;
struct sc_pkcs15_object *obj;
sc_pkcs15_pubkey_t *pubkey = NULL;
sc_pkcs15_cert_t *cert = NULL;
EVP_PKEY *key_out = NULL;
if (!quiet)
fprintf(stderr, "Loading public key!\n");
id = (struct sc_pkcs15_id *) malloc(sizeof(struct sc_pkcs15_id));
id->len = SC_PKCS15_MAX_ID_SIZE;
sc_pkcs15_hex_string_to_id(s_key_id, id);
r = sc_pkcs15_find_pubkey_by_id(p15card, id, &obj);
if (r >= 0) {
if (!quiet)
printf("Reading public key with ID '%s'\n", s_key_id);
r = sc_pkcs15_read_pubkey(p15card, obj, &pubkey);
} else if (r == SC_ERROR_OBJECT_NOT_FOUND) {
/* No pubkey - try if there's a certificate */
r = sc_pkcs15_find_cert_by_id(p15card, id, &obj);
if (r >= 0) {
if (!quiet)
printf("Reading certificate with ID '%s'\n",
s_key_id);
r = sc_pkcs15_read_certificate(p15card,
(sc_pkcs15_cert_info_t *)
obj->data, &cert);
}
if (r >= 0)
pubkey = &cert->key;
}
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
fprintf(stderr, "Public key with ID '%s' not found.\n", s_key_id);
return NULL;
}
if (r < 0) {
fprintf(stderr, "Public key enumeration failed: %s\n",
sc_strerror(r));
return NULL;
}
/* now, set EVP_PKEY data from pubkey object */
key_out = EVP_PKEY_new();
if (!key_out) {
fprintf(stderr, "failed to create new EVP_PKEY\n");
return NULL;
};
EVP_PKEY_assign_RSA(key_out, RSA_new_method(e));
#if 0
RSA_set_method(keyout->rsa, sc_get_rsa_method());
#endif
key_out->pkey.rsa->flags |= RSA_FLAG_EXT_PKEY || RSA_FLAG_SIGN_VER;
RSA_set_app_data(key_out->pkey.rsa, id);
sc_set_pubkey_data(key_out, pubkey);
if (cert)
sc_pkcs15_free_certificate(cert);
else if (pubkey)
sc_pkcs15_free_pubkey(pubkey);
return key_out;
}
char *get_pin(UI_METHOD * ui_method, char *sc_pin, int maxlen)
{
UI *ui;
ui = UI_new();
UI_set_method(ui, ui_method);
if (!UI_add_input_string(ui, "SmartCard Password: ", 0, sc_pin, 1, maxlen)) {
fprintf(stderr, "UI_add_input_string failed");
UI_free(ui);
return NULL;
}
if (UI_process(ui)) {
fprintf(stderr, "UI_process failed");
return NULL;
}
UI_free(ui);
return sc_pin;
}
EVP_PKEY *opensc_load_private_key(ENGINE * e, const char *s_key_id,
UI_METHOD * ui_method, void *callback_data)
{
EVP_PKEY *key_out;
if (!quiet)
fprintf(stderr, "Loading private key!");
if (sc_pin) {
free(sc_pin);
sc_pin = NULL;
}
key_out = opensc_load_public_key(e, s_key_id, ui_method, callback_data);
sc_pin = (char *) malloc(12);
get_pin(ui_method, sc_pin, 12); /* do this here, when storing sc_pin in RSA */
if (!key_out) {
fprintf(stderr, "Failed to get private key");
return NULL;
}
return key_out;
}
int
sc_private_decrypt(int flen, const u_char * from, u_char * to, RSA * rsa,
int padding)
{
struct sc_pkcs15_object *key_obj;
int r;
if (padding != RSA_PKCS1_PADDING)
return -1;
r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_DECRYPT);
if (r)
return -1;
r = sc_pkcs15_decipher(p15card, key_obj, 0, from, flen, to, flen);
sc_unlock(card);
if (r < 0) {
fprintf(stderr, "sc_pkcs15_decipher() failed: %s", sc_strerror(r));
goto err;
}
return r;
err:
return -1;
}
int
sc_sign(int type, const u_char * m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, const RSA * rsa)
{
struct sc_pkcs15_object *key_obj;
int r;
unsigned long flags = 0;
if (!quiet)
fprintf(stderr, "signing with type %d\n", type);
r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_SIGN);
if (r)
return -1;
/* FIXME: length of sigret correct? */
/* FIXME: check 'type' and modify flags accordingly */
flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
if (type == NID_sha1)
flags |= SC_ALGORITHM_RSA_HASH_SHA1;
if (type == NID_md5)
flags |= SC_ALGORITHM_RSA_HASH_MD5;
r = sc_pkcs15_compute_signature(p15card, key_obj, flags,
m, m_len, sigret, RSA_size(rsa));
sc_unlock(card);
if (r < 0) {
fprintf(stderr, "sc_pkcs15_compute_signature() failed: %s",
sc_strerror(r));
goto err;
}
*siglen = r;
return 1;
err:
return 0;
}
int
sc_private_encrypt(int flen, const u_char * from, u_char * to, RSA * rsa,
int padding)
{
fprintf(stderr, "Private key encryption not supported");
return -1;
}