Forgot to remove dead files
This commit is contained in:
parent
6d4f2dd11a
commit
5fe13e2e9b
@ -1,93 +0,0 @@
|
||||
How to use smartcards with OpenSSH?
|
||||
|
||||
OpenSSH contains experimental support for authentication using
|
||||
Cyberflex smartcards and TODOS card readers, in addition to the cards
|
||||
with PKCS#15 structure supported by OpenSC. To enable this you
|
||||
need to:
|
||||
|
||||
Using libsectok:
|
||||
|
||||
(1) enable sectok support in OpenSSH:
|
||||
|
||||
$ ./configure --with-sectok
|
||||
|
||||
(2) If you have used a previous version of ssh with your card, you
|
||||
must remove the old applet and keys.
|
||||
|
||||
$ sectok
|
||||
sectok> login -d
|
||||
sectok> junload Ssh.bin
|
||||
sectok> delete 0012
|
||||
sectok> delete sh
|
||||
sectok> quit
|
||||
|
||||
(3) load the Java Cardlet to the Cyberflex card and set card passphrase:
|
||||
|
||||
$ sectok
|
||||
sectok> login -d
|
||||
sectok> jload /usr/libdata/ssh/Ssh.bin
|
||||
sectok> setpass
|
||||
Enter new AUT0 passphrase:
|
||||
Re-enter passphrase:
|
||||
sectok> quit
|
||||
|
||||
Do not forget the passphrase. There is no way to
|
||||
recover if you do.
|
||||
|
||||
IMPORTANT WARNING: If you attempt to login with the
|
||||
wrong passphrase three times in a row, you will
|
||||
destroy your card.
|
||||
|
||||
(4) load a RSA key to the card:
|
||||
|
||||
$ ssh-keygen -f /path/to/rsakey -U 1
|
||||
(where 1 is the reader number, you can also try 0)
|
||||
|
||||
In spite of the name, this does not generate a key.
|
||||
It just loads an already existing key on to the card.
|
||||
|
||||
(5) Optional: If you don't want to use a card passphrase, change the
|
||||
acl on the private key file:
|
||||
|
||||
$ sectok
|
||||
sectok> login -d
|
||||
sectok> acl 0012 world: w
|
||||
world: w
|
||||
AUT0: w inval
|
||||
sectok> quit
|
||||
|
||||
If you do this, anyone who has access to your card
|
||||
can assume your identity. This is not recommended.
|
||||
|
||||
|
||||
Using OpenSC:
|
||||
|
||||
(1) install OpenSC:
|
||||
|
||||
Sources and instructions are available from
|
||||
http://www.opensc.org/
|
||||
|
||||
(2) enable OpenSC support in OpenSSH:
|
||||
|
||||
$ ./configure --with-opensc[=/path/to/opensc] [options]
|
||||
|
||||
(3) load a RSA key to the card:
|
||||
|
||||
Not supported yet.
|
||||
|
||||
|
||||
Common operations:
|
||||
|
||||
(1) tell the ssh client to use the card reader:
|
||||
|
||||
$ ssh -I 1 otherhost
|
||||
|
||||
(2) or tell the agent (don't forget to restart) to use the smartcard:
|
||||
|
||||
$ ssh-add -s 1
|
||||
|
||||
|
||||
-markus,
|
||||
Tue Jul 17 23:54:51 CEST 2001
|
||||
|
||||
$OpenBSD: README.smartcard,v 1.9 2003/11/21 11:57:02 djm Exp $
|
532
scard-opensc.c
532
scard-opensc.c
@ -1,532 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2002 Juha Yrjölä. All rights reserved.
|
||||
* Copyright (c) 2001 Markus Friedl.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#if defined(SMARTCARD) && defined(USE_OPENSC)
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <opensc/opensc.h>
|
||||
#include <opensc/pkcs15.h>
|
||||
|
||||
#include "key.h"
|
||||
#include "log.h"
|
||||
#include "xmalloc.h"
|
||||
#include "misc.h"
|
||||
#include "scard.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
|
||||
#define USE_ENGINE
|
||||
#define RSA_get_default_method RSA_get_default_openssl_method
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef USE_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#define sc_get_rsa sc_get_engine
|
||||
#else
|
||||
#define sc_get_rsa sc_get_rsa_method
|
||||
#endif
|
||||
|
||||
static int sc_reader_id;
|
||||
static sc_context_t *ctx = NULL;
|
||||
static sc_card_t *card = NULL;
|
||||
static sc_pkcs15_card_t *p15card = NULL;
|
||||
|
||||
static char *sc_pin = NULL;
|
||||
|
||||
struct sc_priv_data
|
||||
{
|
||||
struct sc_pkcs15_id cert_id;
|
||||
int ref_count;
|
||||
};
|
||||
|
||||
void
|
||||
sc_close(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;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sc_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = sc_establish_context(&ctx, "openssh");
|
||||
if (r)
|
||||
goto err;
|
||||
if (sc_reader_id >= ctx->reader_count) {
|
||||
r = SC_ERROR_NO_READERS_FOUND;
|
||||
error("Illegal reader number %d (max %d)", sc_reader_id,
|
||||
ctx->reader_count -1);
|
||||
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 0;
|
||||
err:
|
||||
sc_close();
|
||||
return r;
|
||||
}
|
||||
|
||||
/* private key operations */
|
||||
|
||||
static int
|
||||
sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out,
|
||||
unsigned int usage)
|
||||
{
|
||||
int r;
|
||||
struct sc_priv_data *priv;
|
||||
struct sc_pkcs15_object *key_obj;
|
||||
struct sc_pkcs15_prkey_info *key;
|
||||
struct sc_pkcs15_object *pin_obj;
|
||||
struct sc_pkcs15_pin_info *pin;
|
||||
|
||||
priv = (struct sc_priv_data *) RSA_get_app_data(rsa);
|
||||
if (priv == NULL)
|
||||
return -1;
|
||||
if (p15card == NULL) {
|
||||
sc_close();
|
||||
r = sc_init();
|
||||
if (r) {
|
||||
error("SmartCard init failed: %s", sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
r = sc_pkcs15_find_prkey_by_id_usage(p15card, &priv->cert_id,
|
||||
usage, &key_obj);
|
||||
if (r) {
|
||||
error("Unable to find private key from SmartCard: %s",
|
||||
sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
key = key_obj->data;
|
||||
r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id,
|
||||
&pin_obj);
|
||||
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
||||
/* no pin required */
|
||||
r = sc_lock(card);
|
||||
if (r) {
|
||||
error("Unable to lock smartcard: %s", sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
*key_obj_out = key_obj;
|
||||
return 0;
|
||||
} else if (r) {
|
||||
error("Unable to find PIN object from SmartCard: %s",
|
||||
sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
pin = pin_obj->data;
|
||||
r = sc_lock(card);
|
||||
if (r) {
|
||||
error("Unable to lock smartcard: %s", sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
if (sc_pin != NULL) {
|
||||
r = sc_pkcs15_verify_pin(p15card, pin, sc_pin,
|
||||
strlen(sc_pin));
|
||||
if (r) {
|
||||
sc_unlock(card);
|
||||
error("PIN code verification failed: %s",
|
||||
sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
*key_obj_out = key_obj;
|
||||
return 0;
|
||||
err:
|
||||
sc_close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \
|
||||
SC_PKCS15_PRKEY_USAGE_UNWRAP
|
||||
|
||||
static int
|
||||
sc_private_decrypt(int flen, 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, SC_ALGORITHM_RSA_PAD_PKCS1,
|
||||
from, flen, to, flen);
|
||||
sc_unlock(card);
|
||||
if (r < 0) {
|
||||
error("sc_pkcs15_decipher() failed: %s", sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
return r;
|
||||
err:
|
||||
sc_close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \
|
||||
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
|
||||
|
||||
static int
|
||||
sc_sign(int type, u_char *m, unsigned int m_len,
|
||||
unsigned char *sigret, unsigned int *siglen, RSA *rsa)
|
||||
{
|
||||
struct sc_pkcs15_object *key_obj;
|
||||
int r;
|
||||
unsigned long flags = 0;
|
||||
|
||||
/* XXX: sc_prkey_op_init will search for a pkcs15 private
|
||||
* key object with the sign or signrecover usage flag set.
|
||||
* If the signing key has only the non-repudiation flag set
|
||||
* the key will be rejected as using a non-repudiation key
|
||||
* for authentication is not recommended. Note: This does not
|
||||
* prevent the use of a non-repudiation key for authentication
|
||||
* if the sign or signrecover flag is set as well.
|
||||
*/
|
||||
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 | SC_ALGORITHM_RSA_HASH_SHA1;
|
||||
r = sc_pkcs15_compute_signature(p15card, key_obj, flags,
|
||||
m, m_len, sigret, RSA_size(rsa));
|
||||
sc_unlock(card);
|
||||
if (r < 0) {
|
||||
error("sc_pkcs15_compute_signature() failed: %s",
|
||||
sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
*siglen = r;
|
||||
return 1;
|
||||
err:
|
||||
sc_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
|
||||
int padding)
|
||||
{
|
||||
error("Private key encryption not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* called on free */
|
||||
|
||||
static int (*orig_finish)(RSA *rsa) = NULL;
|
||||
|
||||
static int
|
||||
sc_finish(RSA *rsa)
|
||||
{
|
||||
struct sc_priv_data *priv;
|
||||
|
||||
priv = RSA_get_app_data(rsa);
|
||||
priv->ref_count--;
|
||||
if (priv->ref_count == 0) {
|
||||
free(priv);
|
||||
sc_close();
|
||||
}
|
||||
if (orig_finish)
|
||||
orig_finish(rsa);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* engine for overloading private key operations */
|
||||
|
||||
static RSA_METHOD *
|
||||
sc_get_rsa_method(void)
|
||||
{
|
||||
static RSA_METHOD smart_rsa;
|
||||
const RSA_METHOD *def = RSA_get_default_method();
|
||||
|
||||
/* use the OpenSSL version */
|
||||
memcpy(&smart_rsa, def, sizeof(smart_rsa));
|
||||
|
||||
smart_rsa.name = "opensc";
|
||||
|
||||
/* overload */
|
||||
smart_rsa.rsa_priv_enc = sc_private_encrypt;
|
||||
smart_rsa.rsa_priv_dec = sc_private_decrypt;
|
||||
smart_rsa.rsa_sign = sc_sign;
|
||||
|
||||
/* save original */
|
||||
orig_finish = def->finish;
|
||||
smart_rsa.finish = sc_finish;
|
||||
|
||||
return &smart_rsa;
|
||||
}
|
||||
|
||||
#ifdef USE_ENGINE
|
||||
static ENGINE *
|
||||
sc_get_engine(void)
|
||||
{
|
||||
static ENGINE *smart_engine = NULL;
|
||||
|
||||
if ((smart_engine = ENGINE_new()) == NULL)
|
||||
fatal("ENGINE_new failed");
|
||||
|
||||
ENGINE_set_id(smart_engine, "opensc");
|
||||
ENGINE_set_name(smart_engine, "OpenSC");
|
||||
|
||||
ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
|
||||
ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
|
||||
ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
|
||||
ENGINE_set_RAND(smart_engine, RAND_SSLeay());
|
||||
ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
|
||||
|
||||
return smart_engine;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
convert_rsa_to_rsa1(Key * in, Key * out)
|
||||
{
|
||||
struct sc_priv_data *priv;
|
||||
|
||||
out->rsa->flags = in->rsa->flags;
|
||||
out->flags = in->flags;
|
||||
RSA_set_method(out->rsa, RSA_get_method(in->rsa));
|
||||
BN_copy(out->rsa->n, in->rsa->n);
|
||||
BN_copy(out->rsa->e, in->rsa->e);
|
||||
priv = RSA_get_app_data(in->rsa);
|
||||
priv->ref_count++;
|
||||
RSA_set_app_data(out->rsa, priv);
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj)
|
||||
{
|
||||
int r;
|
||||
sc_pkcs15_cert_t *cert = NULL;
|
||||
struct sc_priv_data *priv = NULL;
|
||||
sc_pkcs15_cert_info_t *cinfo = cert_obj->data;
|
||||
|
||||
X509 *x509 = NULL;
|
||||
EVP_PKEY *pubkey = NULL;
|
||||
u8 *p;
|
||||
char *tmp;
|
||||
|
||||
debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]);
|
||||
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
|
||||
if (r) {
|
||||
logit("Certificate read failed: %s", sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
x509 = X509_new();
|
||||
if (x509 == NULL) {
|
||||
r = -1;
|
||||
goto err;
|
||||
}
|
||||
p = cert->data;
|
||||
if (!d2i_X509(&x509, &p, cert->data_len)) {
|
||||
logit("Unable to parse X.509 certificate");
|
||||
r = -1;
|
||||
goto err;
|
||||
}
|
||||
sc_pkcs15_free_certificate(cert);
|
||||
cert = NULL;
|
||||
pubkey = X509_get_pubkey(x509);
|
||||
X509_free(x509);
|
||||
x509 = NULL;
|
||||
if (pubkey->type != EVP_PKEY_RSA) {
|
||||
logit("Public key is of unknown type");
|
||||
r = -1;
|
||||
goto err;
|
||||
}
|
||||
k->rsa = EVP_PKEY_get1_RSA(pubkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
|
||||
k->rsa->flags |= RSA_FLAG_SIGN_VER;
|
||||
RSA_set_method(k->rsa, sc_get_rsa_method());
|
||||
priv = xmalloc(sizeof(struct sc_priv_data));
|
||||
priv->cert_id = cinfo->id;
|
||||
priv->ref_count = 1;
|
||||
RSA_set_app_data(k->rsa, priv);
|
||||
|
||||
k->flags = KEY_FLAG_EXT;
|
||||
tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
|
||||
debug("fingerprint %d %s", key_size(k), tmp);
|
||||
xfree(tmp);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (cert)
|
||||
sc_pkcs15_free_certificate(cert);
|
||||
if (pubkey)
|
||||
EVP_PKEY_free(pubkey);
|
||||
if (x509)
|
||||
X509_free(x509);
|
||||
return r;
|
||||
}
|
||||
|
||||
Key **
|
||||
sc_get_keys(const char *id, const char *pin)
|
||||
{
|
||||
Key *k, **keys;
|
||||
int i, r, real_count = 0, key_count;
|
||||
sc_pkcs15_id_t cert_id;
|
||||
sc_pkcs15_object_t *certs[32];
|
||||
char *buf = xstrdup(id), *p;
|
||||
|
||||
debug("sc_get_keys called: id = %s", id);
|
||||
|
||||
if (sc_pin != NULL)
|
||||
xfree(sc_pin);
|
||||
sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
|
||||
|
||||
cert_id.len = 0;
|
||||
if ((p = strchr(buf, ':')) != NULL) {
|
||||
*p = 0;
|
||||
p++;
|
||||
sc_pkcs15_hex_string_to_id(p, &cert_id);
|
||||
}
|
||||
r = sscanf(buf, "%d", &sc_reader_id);
|
||||
xfree(buf);
|
||||
if (r != 1)
|
||||
goto err;
|
||||
if (p15card == NULL) {
|
||||
sc_close();
|
||||
r = sc_init();
|
||||
if (r) {
|
||||
error("Smartcard init failed: %s", sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (cert_id.len) {
|
||||
r = sc_pkcs15_find_cert_by_id(p15card, &cert_id, &certs[0]);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
key_count = 1;
|
||||
} else {
|
||||
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509,
|
||||
certs, 32);
|
||||
if (r == 0) {
|
||||
logit("No certificates found on smartcard");
|
||||
r = -1;
|
||||
goto err;
|
||||
} else if (r < 0) {
|
||||
error("Certificate enumeration failed: %s",
|
||||
sc_strerror(r));
|
||||
goto err;
|
||||
}
|
||||
key_count = r;
|
||||
}
|
||||
if (key_count > 1024)
|
||||
fatal("Too many keys (%u), expected <= 1024", key_count);
|
||||
keys = xcalloc(key_count * 2 + 1, sizeof(Key *));
|
||||
for (i = 0; i < key_count; i++) {
|
||||
sc_pkcs15_object_t *tmp_obj = NULL;
|
||||
cert_id = ((sc_pkcs15_cert_info_t *)(certs[i]->data))->id;
|
||||
if (sc_pkcs15_find_prkey_by_id(p15card, &cert_id, &tmp_obj))
|
||||
/* skip the public key (certificate) if no
|
||||
* corresponding private key is present */
|
||||
continue;
|
||||
k = key_new(KEY_RSA);
|
||||
if (k == NULL)
|
||||
break;
|
||||
r = sc_read_pubkey(k, certs[i]);
|
||||
if (r) {
|
||||
error("sc_read_pubkey failed: %s", sc_strerror(r));
|
||||
key_free(k);
|
||||
continue;
|
||||
}
|
||||
keys[real_count] = k;
|
||||
real_count++;
|
||||
k = key_new(KEY_RSA1);
|
||||
if (k == NULL)
|
||||
break;
|
||||
convert_rsa_to_rsa1(keys[real_count-1], k);
|
||||
keys[real_count] = k;
|
||||
real_count++;
|
||||
}
|
||||
keys[real_count] = NULL;
|
||||
|
||||
return keys;
|
||||
err:
|
||||
sc_close();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
sc_put_key(Key *prv, const char *id)
|
||||
{
|
||||
error("key uploading not yet supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
sc_get_key_label(Key *key)
|
||||
{
|
||||
int r;
|
||||
const struct sc_priv_data *priv;
|
||||
struct sc_pkcs15_object *key_obj;
|
||||
|
||||
priv = (const struct sc_priv_data *) RSA_get_app_data(key->rsa);
|
||||
if (priv == NULL || p15card == NULL) {
|
||||
logit("SmartCard key not loaded");
|
||||
/* internal error => return default label */
|
||||
return xstrdup("smartcard key");
|
||||
}
|
||||
r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj);
|
||||
if (r) {
|
||||
logit("Unable to find private key from SmartCard: %s",
|
||||
sc_strerror(r));
|
||||
return xstrdup("smartcard key");
|
||||
}
|
||||
if (key_obj == NULL || key_obj->label == NULL)
|
||||
/* the optional PKCS#15 label does not exists
|
||||
* => return the default label */
|
||||
return xstrdup("smartcard key");
|
||||
return xstrdup(key_obj->label);
|
||||
}
|
||||
|
||||
#endif /* SMARTCARD */
|
571
scard.c
571
scard.c
@ -1,571 +0,0 @@
|
||||
/* $OpenBSD: scard.c,v 1.36 2006/11/06 21:25:28 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#if defined(SMARTCARD) && defined(USE_SECTOK)
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sectok.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "scard.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x00907000L
|
||||
#define USE_ENGINE
|
||||
#define RSA_get_default_method RSA_get_default_openssl_method
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef USE_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#define sc_get_rsa sc_get_engine
|
||||
#else
|
||||
#define sc_get_rsa sc_get_rsa_method
|
||||
#endif
|
||||
|
||||
#define CLA_SSH 0x05
|
||||
#define INS_DECRYPT 0x10
|
||||
#define INS_GET_KEYLENGTH 0x20
|
||||
#define INS_GET_PUBKEY 0x30
|
||||
#define INS_GET_RESPONSE 0xc0
|
||||
|
||||
#define MAX_BUF_SIZE 256
|
||||
|
||||
u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
|
||||
|
||||
static int sc_fd = -1;
|
||||
static char *sc_reader_id = NULL;
|
||||
static char *sc_pin = NULL;
|
||||
static int cla = 0x00; /* class */
|
||||
|
||||
static void sc_mk_digest(const char *pin, u_char *digest);
|
||||
static int get_AUT0(u_char *aut0);
|
||||
static int try_AUT0(void);
|
||||
|
||||
/* interface to libsectok */
|
||||
|
||||
static int
|
||||
sc_open(void)
|
||||
{
|
||||
int sw;
|
||||
|
||||
if (sc_fd >= 0)
|
||||
return sc_fd;
|
||||
|
||||
sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
|
||||
if (sc_fd < 0) {
|
||||
error("sectok_open failed: %s", sectok_get_sw(sw));
|
||||
return SCARD_ERROR_FAIL;
|
||||
}
|
||||
if (! sectok_cardpresent(sc_fd)) {
|
||||
debug("smartcard in reader %s not present, skipping",
|
||||
sc_reader_id);
|
||||
sc_close();
|
||||
return SCARD_ERROR_NOCARD;
|
||||
}
|
||||
if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
|
||||
error("sectok_reset failed: %s", sectok_get_sw(sw));
|
||||
sc_fd = -1;
|
||||
return SCARD_ERROR_FAIL;
|
||||
}
|
||||
if ((cla = cyberflex_inq_class(sc_fd)) < 0)
|
||||
cla = 0;
|
||||
|
||||
debug("sc_open ok %d", sc_fd);
|
||||
return sc_fd;
|
||||
}
|
||||
|
||||
static int
|
||||
sc_enable_applet(void)
|
||||
{
|
||||
static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
|
||||
int sw = 0;
|
||||
|
||||
/* select applet id */
|
||||
sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
|
||||
if (!sectok_swOK(sw)) {
|
||||
error("sectok_apdu failed: %s", sectok_get_sw(sw));
|
||||
sc_close();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sc_init(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = sc_open();
|
||||
if (status == SCARD_ERROR_NOCARD) {
|
||||
return SCARD_ERROR_NOCARD;
|
||||
}
|
||||
if (status < 0) {
|
||||
error("sc_open failed");
|
||||
return status;
|
||||
}
|
||||
if (sc_enable_applet() < 0) {
|
||||
error("sc_enable_applet failed");
|
||||
return SCARD_ERROR_APPLET;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sc_read_pubkey(Key * k)
|
||||
{
|
||||
u_char buf[2], *n;
|
||||
char *p;
|
||||
int len, sw, status = -1;
|
||||
|
||||
len = sw = 0;
|
||||
n = NULL;
|
||||
|
||||
if (sc_fd < 0) {
|
||||
if (sc_init() < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* get key size */
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
|
||||
sizeof(buf), buf, &sw);
|
||||
if (!sectok_swOK(sw)) {
|
||||
error("could not obtain key length: %s", sectok_get_sw(sw));
|
||||
goto err;
|
||||
}
|
||||
len = (buf[0] << 8) | buf[1];
|
||||
len /= 8;
|
||||
debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
|
||||
|
||||
n = xmalloc(len);
|
||||
/* get n */
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
|
||||
|
||||
if (sw == 0x6982) {
|
||||
if (try_AUT0() < 0)
|
||||
goto err;
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
|
||||
}
|
||||
if (!sectok_swOK(sw)) {
|
||||
error("could not obtain public key: %s", sectok_get_sw(sw));
|
||||
goto err;
|
||||
}
|
||||
|
||||
debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
|
||||
|
||||
if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
|
||||
error("c_read_pubkey: BN_bin2bn failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* currently the java applet just stores 'n' */
|
||||
if (!BN_set_word(k->rsa->e, 35)) {
|
||||
error("c_read_pubkey: BN_set_word(e, 35) failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
|
||||
debug("fingerprint %u %s", key_size(k), p);
|
||||
xfree(p);
|
||||
|
||||
err:
|
||||
if (n != NULL)
|
||||
xfree(n);
|
||||
sc_close();
|
||||
return status;
|
||||
}
|
||||
|
||||
/* private key operations */
|
||||
|
||||
static int
|
||||
sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
|
||||
int padding)
|
||||
{
|
||||
u_char *padded = NULL;
|
||||
int sw, len, olen, status = -1;
|
||||
|
||||
debug("sc_private_decrypt called");
|
||||
|
||||
olen = len = sw = 0;
|
||||
if (sc_fd < 0) {
|
||||
status = sc_init();
|
||||
if (status < 0)
|
||||
goto err;
|
||||
}
|
||||
if (padding != RSA_PKCS1_PADDING)
|
||||
goto err;
|
||||
|
||||
len = BN_num_bytes(rsa->n);
|
||||
padded = xmalloc(len);
|
||||
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
|
||||
|
||||
if (sw == 0x6982) {
|
||||
if (try_AUT0() < 0)
|
||||
goto err;
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
|
||||
}
|
||||
if (!sectok_swOK(sw)) {
|
||||
error("sc_private_decrypt: INS_DECRYPT failed: %s",
|
||||
sectok_get_sw(sw));
|
||||
goto err;
|
||||
}
|
||||
olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
|
||||
len);
|
||||
err:
|
||||
if (padded)
|
||||
xfree(padded);
|
||||
sc_close();
|
||||
return (olen >= 0 ? olen : status);
|
||||
}
|
||||
|
||||
static int
|
||||
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
|
||||
int padding)
|
||||
{
|
||||
u_char *padded = NULL;
|
||||
int sw, len, status = -1;
|
||||
|
||||
len = sw = 0;
|
||||
if (sc_fd < 0) {
|
||||
status = sc_init();
|
||||
if (status < 0)
|
||||
goto err;
|
||||
}
|
||||
if (padding != RSA_PKCS1_PADDING)
|
||||
goto err;
|
||||
|
||||
debug("sc_private_encrypt called");
|
||||
len = BN_num_bytes(rsa->n);
|
||||
padded = xmalloc(len);
|
||||
|
||||
if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) {
|
||||
error("RSA_padding_add_PKCS1_type_1 failed");
|
||||
goto err;
|
||||
}
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
|
||||
if (sw == 0x6982) {
|
||||
if (try_AUT0() < 0)
|
||||
goto err;
|
||||
sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
|
||||
}
|
||||
if (!sectok_swOK(sw)) {
|
||||
error("sc_private_encrypt: INS_DECRYPT failed: %s",
|
||||
sectok_get_sw(sw));
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
if (padded)
|
||||
xfree(padded);
|
||||
sc_close();
|
||||
return (len >= 0 ? len : status);
|
||||
}
|
||||
|
||||
/* called on free */
|
||||
|
||||
static int (*orig_finish)(RSA *rsa) = NULL;
|
||||
|
||||
static int
|
||||
sc_finish(RSA *rsa)
|
||||
{
|
||||
if (orig_finish)
|
||||
orig_finish(rsa);
|
||||
sc_close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* engine for overloading private key operations */
|
||||
|
||||
static RSA_METHOD *
|
||||
sc_get_rsa_method(void)
|
||||
{
|
||||
static RSA_METHOD smart_rsa;
|
||||
const RSA_METHOD *def = RSA_get_default_method();
|
||||
|
||||
/* use the OpenSSL version */
|
||||
memcpy(&smart_rsa, def, sizeof(smart_rsa));
|
||||
|
||||
smart_rsa.name = "sectok";
|
||||
|
||||
/* overload */
|
||||
smart_rsa.rsa_priv_enc = sc_private_encrypt;
|
||||
smart_rsa.rsa_priv_dec = sc_private_decrypt;
|
||||
|
||||
/* save original */
|
||||
orig_finish = def->finish;
|
||||
smart_rsa.finish = sc_finish;
|
||||
|
||||
return &smart_rsa;
|
||||
}
|
||||
|
||||
#ifdef USE_ENGINE
|
||||
static ENGINE *
|
||||
sc_get_engine(void)
|
||||
{
|
||||
static ENGINE *smart_engine = NULL;
|
||||
|
||||
if ((smart_engine = ENGINE_new()) == NULL)
|
||||
fatal("ENGINE_new failed");
|
||||
|
||||
ENGINE_set_id(smart_engine, "sectok");
|
||||
ENGINE_set_name(smart_engine, "libsectok");
|
||||
|
||||
ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
|
||||
ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
|
||||
ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
|
||||
ENGINE_set_RAND(smart_engine, RAND_SSLeay());
|
||||
ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
|
||||
|
||||
return smart_engine;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
sc_close(void)
|
||||
{
|
||||
if (sc_fd >= 0) {
|
||||
sectok_close(sc_fd);
|
||||
sc_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
Key **
|
||||
sc_get_keys(const char *id, const char *pin)
|
||||
{
|
||||
Key *k, *n, **keys;
|
||||
int status, nkeys = 2;
|
||||
|
||||
if (sc_reader_id != NULL)
|
||||
xfree(sc_reader_id);
|
||||
sc_reader_id = xstrdup(id);
|
||||
|
||||
if (sc_pin != NULL)
|
||||
xfree(sc_pin);
|
||||
sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
|
||||
|
||||
k = key_new(KEY_RSA);
|
||||
if (k == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
status = sc_read_pubkey(k);
|
||||
if (status == SCARD_ERROR_NOCARD) {
|
||||
key_free(k);
|
||||
return NULL;
|
||||
}
|
||||
if (status < 0) {
|
||||
error("sc_read_pubkey failed");
|
||||
key_free(k);
|
||||
return NULL;
|
||||
}
|
||||
keys = xcalloc((nkeys+1), sizeof(Key *));
|
||||
|
||||
n = key_new(KEY_RSA1);
|
||||
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
|
||||
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
|
||||
fatal("sc_get_keys: BN_copy failed");
|
||||
RSA_set_method(n->rsa, sc_get_rsa());
|
||||
n->flags |= KEY_FLAG_EXT;
|
||||
keys[0] = n;
|
||||
|
||||
n = key_new(KEY_RSA);
|
||||
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
|
||||
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
|
||||
fatal("sc_get_keys: BN_copy failed");
|
||||
RSA_set_method(n->rsa, sc_get_rsa());
|
||||
n->flags |= KEY_FLAG_EXT;
|
||||
keys[1] = n;
|
||||
|
||||
keys[2] = NULL;
|
||||
|
||||
key_free(k);
|
||||
return keys;
|
||||
}
|
||||
|
||||
#define NUM_RSA_KEY_ELEMENTS 5+1
|
||||
#define COPY_RSA_KEY(x, i) \
|
||||
do { \
|
||||
len = BN_num_bytes(prv->rsa->x); \
|
||||
elements[i] = xmalloc(len); \
|
||||
debug("#bytes %d", len); \
|
||||
if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \
|
||||
goto done; \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
sc_mk_digest(const char *pin, u_char *digest)
|
||||
{
|
||||
const EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, pin, strlen(pin));
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
get_AUT0(u_char *aut0)
|
||||
{
|
||||
char *pass;
|
||||
|
||||
pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
|
||||
if (pass == NULL)
|
||||
return -1;
|
||||
if (!strcmp(pass, "-")) {
|
||||
memcpy(aut0, DEFAUT0, sizeof DEFAUT0);
|
||||
return 0;
|
||||
}
|
||||
sc_mk_digest(pass, aut0);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
try_AUT0(void)
|
||||
{
|
||||
u_char aut0[EVP_MAX_MD_SIZE];
|
||||
|
||||
/* permission denied; try PIN if provided */
|
||||
if (sc_pin && strlen(sc_pin) > 0) {
|
||||
sc_mk_digest(sc_pin, aut0);
|
||||
if (cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
|
||||
error("smartcard passphrase incorrect");
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
/* try default AUT0 key */
|
||||
if (cyberflex_verify_AUT0(sc_fd, cla, DEFAUT0, 8) < 0) {
|
||||
/* default AUT0 key failed; prompt for passphrase */
|
||||
if (get_AUT0(aut0) < 0 ||
|
||||
cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
|
||||
error("smartcard passphrase incorrect");
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sc_put_key(Key *prv, const char *id)
|
||||
{
|
||||
u_char *elements[NUM_RSA_KEY_ELEMENTS];
|
||||
u_char key_fid[2];
|
||||
u_char AUT0[EVP_MAX_MD_SIZE];
|
||||
int len, status = -1, i, fd = -1, ret;
|
||||
int sw = 0, cla = 0x00;
|
||||
|
||||
for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
|
||||
elements[i] = NULL;
|
||||
|
||||
COPY_RSA_KEY(q, 0);
|
||||
COPY_RSA_KEY(p, 1);
|
||||
COPY_RSA_KEY(iqmp, 2);
|
||||
COPY_RSA_KEY(dmq1, 3);
|
||||
COPY_RSA_KEY(dmp1, 4);
|
||||
COPY_RSA_KEY(n, 5);
|
||||
len = BN_num_bytes(prv->rsa->n);
|
||||
fd = sectok_friendly_open(id, STONOWAIT, &sw);
|
||||
if (fd < 0) {
|
||||
error("sectok_open failed: %s", sectok_get_sw(sw));
|
||||
goto done;
|
||||
}
|
||||
if (! sectok_cardpresent(fd)) {
|
||||
error("smartcard in reader %s not present", id);
|
||||
goto done;
|
||||
}
|
||||
ret = sectok_reset(fd, 0, NULL, &sw);
|
||||
if (ret <= 0) {
|
||||
error("sectok_reset failed: %s", sectok_get_sw(sw));
|
||||
goto done;
|
||||
}
|
||||
if ((cla = cyberflex_inq_class(fd)) < 0) {
|
||||
error("cyberflex_inq_class failed");
|
||||
goto done;
|
||||
}
|
||||
memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0));
|
||||
if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
|
||||
if (get_AUT0(AUT0) < 0 ||
|
||||
cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
|
||||
memset(AUT0, 0, sizeof(DEFAUT0));
|
||||
error("smartcard passphrase incorrect");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
memset(AUT0, 0, sizeof(DEFAUT0));
|
||||
key_fid[0] = 0x00;
|
||||
key_fid[1] = 0x12;
|
||||
if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements,
|
||||
&sw) < 0) {
|
||||
error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw));
|
||||
goto done;
|
||||
}
|
||||
if (!sectok_swOK(sw))
|
||||
goto done;
|
||||
logit("cyberflex_load_rsa_priv done");
|
||||
key_fid[0] = 0x73;
|
||||
key_fid[1] = 0x68;
|
||||
if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5],
|
||||
&sw) < 0) {
|
||||
error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw));
|
||||
goto done;
|
||||
}
|
||||
if (!sectok_swOK(sw))
|
||||
goto done;
|
||||
logit("cyberflex_load_rsa_pub done");
|
||||
status = 0;
|
||||
|
||||
done:
|
||||
memset(elements[0], '\0', BN_num_bytes(prv->rsa->q));
|
||||
memset(elements[1], '\0', BN_num_bytes(prv->rsa->p));
|
||||
memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp));
|
||||
memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1));
|
||||
memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1));
|
||||
memset(elements[5], '\0', BN_num_bytes(prv->rsa->n));
|
||||
|
||||
for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
|
||||
if (elements[i])
|
||||
xfree(elements[i]);
|
||||
if (fd != -1)
|
||||
sectok_close(fd);
|
||||
return (status);
|
||||
}
|
||||
|
||||
char *
|
||||
sc_get_key_label(Key *key)
|
||||
{
|
||||
return xstrdup("smartcard key");
|
||||
}
|
||||
|
||||
#endif /* SMARTCARD && USE_SECTOK */
|
39
scard.h
39
scard.h
@ -1,39 +0,0 @@
|
||||
/* $OpenBSD: scard.h,v 1.14 2006/08/03 03:34:42 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SCARD_H
|
||||
#define SCARD_H
|
||||
|
||||
#define SCARD_ERROR_FAIL -1
|
||||
#define SCARD_ERROR_NOCARD -2
|
||||
#define SCARD_ERROR_APPLET -3
|
||||
|
||||
Key **sc_get_keys(const char *, const char *);
|
||||
void sc_close(void);
|
||||
int sc_put_key(Key *, const char *);
|
||||
char *sc_get_key_label(Key *);
|
||||
|
||||
#endif
|
@ -1,29 +0,0 @@
|
||||
# $Id: Makefile.in,v 1.5 2006/10/23 21:44:47 tim Exp $
|
||||
|
||||
prefix=@prefix@
|
||||
datadir=@datadir@
|
||||
datarootdir=@datarootdir@
|
||||
srcdir=@srcdir@
|
||||
top_srcdir=@top_srcdir@
|
||||
|
||||
INSTALL=@INSTALL@
|
||||
|
||||
VPATH=@srcdir@
|
||||
|
||||
all:
|
||||
|
||||
#Ssh.bin: Ssh.bin.uu
|
||||
# uudecode Ssh.bin.uu
|
||||
|
||||
clean:
|
||||
# rm -rf Ssh.bin
|
||||
|
||||
distprep:
|
||||
uudecode Ssh.bin.uu
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile *~
|
||||
|
||||
install: $(srcdir)/Ssh.bin
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(datadir)
|
||||
$(INSTALL) -m 0644 $(srcdir)/Ssh.bin $(DESTDIR)$(datadir)/Ssh.bin
|
BIN
scard/Ssh.bin
BIN
scard/Ssh.bin
Binary file not shown.
@ -1,17 +0,0 @@
|
||||
begin 644 Ssh.bin
|
||||
M`P)!&P`801X`>``!`E@"`/Y@\`4`_J'P!0!!&T$=`?Z@\`4`01M!'`'^>/,!
|
||||
M`4$;01X!_G#S%P'^0],1`?Y@\!0`_G/S'0#^<]4``D$;L`4`_F'3``#^8=,%
|
||||
M`/ZAT`$!_J#0)P'^H],*`?ZCTPD`_G/5"P7^8=,'`OZAT`H`_J#0$@3^:-,@
|
||||
M`T$;`P`%`/Y@`<P``$$<\@\``$$=\B$``$$>\A```/`0__(%`@8!`0H``&``
|
||||
M0205!!D)I$L`"0J0`&``*!4$&58``````.P````%____P````.D````0````
|
||||
M,P```"````#'````,````(T````R````V!4#&0A*``D*;@!@`"@5!QD*`/\]
|
||||
M(6``1A)*``D*9P!@`"@*/P!@`$LK"1)@`$LK!6``4!P$#00#2@`.#01@`%5@
|
||||
M`%I@`"@37``>%0@2%0A>`%\($F``9%(`:`H_`&``2RL*<VA@`$LK8`!I"1`U
|
||||
M(14#`Q)@`&X<!`T$`TL`"P,28`!D4@`.#01@`%5@`%I@`"A2`"X5`PH$`&``
|
||||
M<RL#!6``9%(`'14#"@$"8`!S*P,%8`!D4@`,4@`)"FT`8``H60``\`+_\@$!
|
||||
M`0D`"```"I``8``H60#P$__R`0$""0`,``!B01LM7P`\*UD```#P$O_V`0$#
|
||||
M`0`8```37``>7@`R10`/$UP`'@H`R`D07@`W!%>P!?_R`0$$`@`\```37P``
|
||||
M$V+^H2U?``5=``H38OZ@+5\`#UT`%!-B_G@M"@0`7P`970`>"@0`8``C10`)
|
||||
/"F<`8``H$UX`+5D`````
|
||||
`
|
||||
end
|
164
scard/Ssh.java
164
scard/Ssh.java
@ -1,164 +0,0 @@
|
||||
// $Id: Ssh.java,v 1.3 2002/05/22 04:24:02 djm Exp $
|
||||
//
|
||||
// Ssh.java
|
||||
// SSH / smartcard integration project, smartcard side
|
||||
//
|
||||
// Tomoko Fukuzawa, created, Feb., 2000
|
||||
//
|
||||
// Naomaru Itoi, modified, Apr., 2000
|
||||
//
|
||||
|
||||
// copyright 2000
|
||||
// the regents of the university of michigan
|
||||
// all rights reserved
|
||||
//
|
||||
// permission is granted to use, copy, create derivative works
|
||||
// and redistribute this software and such derivative works
|
||||
// for any purpose, so long as the name of the university of
|
||||
// michigan is not used in any advertising or publicity
|
||||
// pertaining to the use or distribution of this software
|
||||
// without specific, written prior authorization. if the
|
||||
// above copyright notice or any other identification of the
|
||||
// university of michigan is included in any copy of any
|
||||
// portion of this software, then the disclaimer below must
|
||||
// also be included.
|
||||
//
|
||||
// this software is provided as is, without representation
|
||||
// from the university of michigan as to its fitness for any
|
||||
// purpose, and without warranty by the university of
|
||||
// michigan of any kind, either express or implied, including
|
||||
// without limitation the implied warranties of
|
||||
// merchantability and fitness for a particular purpose. the
|
||||
// regents of the university of michigan shall not be liable
|
||||
// for any damages, including special, indirect, incidental, or
|
||||
// consequential damages, with respect to any claim arising
|
||||
// out of or in connection with the use of the software, even
|
||||
// if it has been or is hereafter advised of the possibility of
|
||||
// such damages.
|
||||
|
||||
import javacard.framework.*;
|
||||
import javacardx.framework.*;
|
||||
import javacardx.crypto.*;
|
||||
|
||||
public class Ssh extends javacard.framework.Applet
|
||||
{
|
||||
// Change this when the applet changes; hi byte is major, low byte is minor
|
||||
static final short applet_version = (short)0x0102;
|
||||
|
||||
/* constants declaration */
|
||||
// code of CLA byte in the command APDU header
|
||||
static final byte Ssh_CLA =(byte)0x05;
|
||||
|
||||
// codes of INS byte in the command APDU header
|
||||
static final byte DECRYPT = (byte) 0x10;
|
||||
static final byte GET_KEYLENGTH = (byte) 0x20;
|
||||
static final byte GET_PUBKEY = (byte) 0x30;
|
||||
static final byte GET_VERSION = (byte) 0x32;
|
||||
static final byte GET_RESPONSE = (byte) 0xc0;
|
||||
|
||||
static final short keysize = 1024;
|
||||
static final short root_fid = (short)0x3f00;
|
||||
static final short privkey_fid = (short)0x0012;
|
||||
static final short pubkey_fid = (short)(('s'<<8)|'h');
|
||||
|
||||
/* instance variables declaration */
|
||||
AsymKey rsakey;
|
||||
CyberflexFile file;
|
||||
CyberflexOS os;
|
||||
|
||||
private Ssh()
|
||||
{
|
||||
file = new CyberflexFile();
|
||||
os = new CyberflexOS();
|
||||
|
||||
rsakey = new RSA_CRT_PrivateKey (keysize);
|
||||
|
||||
if ( ! rsakey.isSupportedLength (keysize) )
|
||||
ISOException.throwIt (ISO.SW_WRONG_LENGTH);
|
||||
|
||||
register();
|
||||
} // end of the constructor
|
||||
|
||||
public boolean select() {
|
||||
if (!rsakey.isInitialized())
|
||||
rsakey.setKeyInstance ((short)0xc8, (short)0x10);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void install(APDU apdu)
|
||||
{
|
||||
new Ssh(); // create a Ssh applet instance (card)
|
||||
} // end of install method
|
||||
|
||||
public static void main(String args[]) {
|
||||
ISOException.throwIt((short) 0x9000);
|
||||
}
|
||||
|
||||
public void process(APDU apdu)
|
||||
{
|
||||
// APDU object carries a byte array (buffer) to
|
||||
// transfer incoming and outgoing APDU header
|
||||
// and data bytes between card and CAD
|
||||
byte buffer[] = apdu.getBuffer();
|
||||
short size, st;
|
||||
|
||||
// verify that if the applet can accept this
|
||||
// APDU message
|
||||
// NI: change suggested by Wayne Dyksen, Purdue
|
||||
if (buffer[ISO.OFFSET_INS] == ISO.INS_SELECT)
|
||||
ISOException.throwIt(ISO.SW_NO_ERROR);
|
||||
|
||||
switch (buffer[ISO.OFFSET_INS]) {
|
||||
case DECRYPT:
|
||||
if (buffer[ISO.OFFSET_CLA] != Ssh_CLA)
|
||||
ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);
|
||||
//decrypt (apdu);
|
||||
size = (short) (buffer[ISO.OFFSET_LC] & 0x00FF);
|
||||
|
||||
if (apdu.setIncomingAndReceive() != size)
|
||||
ISOException.throwIt (ISO.SW_WRONG_LENGTH);
|
||||
|
||||
// check access; depends on bit 2 (x/a)
|
||||
file.selectFile(root_fid);
|
||||
file.selectFile(privkey_fid);
|
||||
st = os.checkAccess(ACL.EXECUTE);
|
||||
if (st != ST.ACCESS_CLEARED) {
|
||||
CyberflexAPDU.prepareSW1SW2(st);
|
||||
ISOException.throwIt(CyberflexAPDU.getSW1SW2());
|
||||
}
|
||||
|
||||
rsakey.cryptoUpdate (buffer, (short) ISO.OFFSET_CDATA, size,
|
||||
buffer, (short) ISO.OFFSET_CDATA);
|
||||
|
||||
apdu.setOutgoingAndSend ((short) ISO.OFFSET_CDATA, size);
|
||||
break;
|
||||
case GET_PUBKEY:
|
||||
file.selectFile(root_fid); // select root
|
||||
file.selectFile(pubkey_fid); // select public key file
|
||||
size = (short)(file.getFileSize() - 16);
|
||||
st = os.readBinaryFile(buffer, (short)0, (short)0, size);
|
||||
if (st == ST.SUCCESS)
|
||||
apdu.setOutgoingAndSend((short)0, size);
|
||||
else {
|
||||
CyberflexAPDU.prepareSW1SW2(st);
|
||||
ISOException.throwIt(CyberflexAPDU.getSW1SW2());
|
||||
}
|
||||
break;
|
||||
case GET_KEYLENGTH:
|
||||
Util.setShort(buffer, (short)0, keysize);
|
||||
apdu.setOutgoingAndSend ((short)0, (short)2);
|
||||
break;
|
||||
case GET_VERSION:
|
||||
Util.setShort(buffer, (short)0, applet_version);
|
||||
apdu.setOutgoingAndSend ((short)0, (short)2);
|
||||
break;
|
||||
case GET_RESPONSE:
|
||||
break;
|
||||
default:
|
||||
ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
} // end of process method
|
||||
|
||||
} // end of class Ssh
|
Loading…
Reference in New Issue
Block a user