⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smartcard.c

📁 This a good VPN source
💻 C
字号:
/* Support of smartcards and cryptotokens * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen * Zuercher Hochschule Winterthur * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>. * * This program 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 General Public License * for more details. * * RCSID $Id: smartcard.c,v 1.6 2004/09/22 15:47:07 paul Exp $ */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <string.h>#ifdef SMARTCARD#include <opensc/opensc.h>#include <opensc/pkcs15.h>#endif#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "defs.h"#include "id.h"#include "log.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#include "whack.h"#include "fetch.h"#define BUF_LEN	      512	/* buffer size *//* chained list of smartcard records */static smartcard_t *smartcards   = NULL;#ifdef SMARTCARD	/* compile with smartcard support */static struct sc_context *ctx = NULL;static struct sc_card *card = NULL;static struct sc_pkcs15_card *p15card = NULL;#endif/* * Connect to the card in card reader card_reader, lock and bind it * * Status information and context is saved in the * global variables ctx, card and p15card */boolscx_establish_context(u_int card_reader USED_BY_SMARTCARD){#ifdef SMARTCARD    int r;    /* establish a context */    r = sc_establish_context(&ctx, "pluto");    if (r)    {	plog("failed to establish context: %s", sc_strerror(r));	return FALSE;    }    /* test if reader card_reader is available */    if (card_reader >= (unsigned int) ctx->reader_count)    {	plog("illegal reader number - only %d reader(s) configured."	    , ctx->reader_count);	return FALSE;    }    /* test if card is inserted */     r = sc_detect_card_presence(ctx->reader[card_reader], 0);    if (!(r & SC_SLOT_CARD_PRESENT))    {	plog("card not present: %s", sc_strerror(r));	return FALSE;    }    DBG(DBG_CONTROL | DBG_CRYPT,	DBG_log("connecting to card in reader %s..."	    , ctx->reader[card_reader]->name)    )    /* connect to the card */    r = sc_connect_card(ctx->reader[card_reader], 0, &card);    if (r)    {	plog("failed to connect to card: %s", sc_strerror(r));	return FALSE;    }    /* lock card, so it can't be used by another application */    r = sc_lock(card);    if (r)    {	plog("unable to lock card: %s", sc_strerror(r));	return FALSE;    }    /* establish context for pkcs15-functions */    r = sc_pkcs15_bind(card, &p15card);    if (r)    {	plog("PKCS #15 initialization failed: %s", sc_strerror(r));	return FALSE;    }    DBG(DBG_CONTROL | DBG_CRYPT,	DBG_log("found %s!", p15card->label)    )    return TRUE;#else    plog("warning: SMARTCARD support is deactivated in pluto/Makefile!");    return FALSE;#endif}/* * Release context and disconnect from card */voidscx_release_context(void){#ifdef SMARTCARD    if (p15card != NULL)    {	/* release pkcs15-context */	sc_pkcs15_unbind(p15card);	p15card = NULL;    }    if (card != NULL)    {	/* unlock und disconnect from card */	sc_unlock(card);	sc_disconnect_card(card, 0);	card = NULL;    }    if (ctx != NULL)    {	/* release context */	sc_release_context(ctx);	ctx = NULL;    }#endif}/* * Load host certificate from smartcard */boolscx_load_cert(smartcard_t *sc UNUSED, cert_t * cert UNUSED){#ifdef SMARTCARD	/* compile with smartcard support */    struct sc_pkcs15_id id;    struct sc_pkcs15_cert *card_cert = NULL;    struct sc_pkcs15_object *cert_obj;    struct sc_pkcs15_cert_info *cinfo;    x509cert_t *x509cert;    chunk_t blob;    int r;    /* establish context */    if (!scx_establish_context(sc->reader))    {	scx_release_context();	return FALSE;    }    /* convert id-string to pkcs15-id */    id.len = SC_PKCS15_MAX_ID_SIZE;    sc_pkcs15_hex_string_to_id(sc->id, &id);    /* get info for certificate with id */    r = sc_pkcs15_find_cert_by_id(p15card, &id, &cert_obj);    if (r < 0)    {	plog("unable to find cert with id %s: %s", sc->id, sc_strerror(r));	scx_release_context();	return FALSE;    }    cinfo = (struct sc_pkcs15_cert_info *) cert_obj->data;    /* read certificate */    r = sc_pkcs15_read_certificate(p15card, cinfo, &card_cert);    if (r)    {	plog("certificate read failed: %s", sc_strerror(r));	scx_release_context();	return FALSE;    }    scx_release_context();    if (card_cert == NULL)    {	plog( "cert with id %s not found.", sc->id);	return FALSE;    }    /* found and read certificate - now parse it */    x509cert = alloc_thing(x509cert_t, "x509cert");    *x509cert = empty_x509cert;    x509cert->smartcard = TRUE;    /* copy and release certificate */    clonetochunk(blob, card_cert->data, card_cert->data_len, "x509cert blob");    sc_pkcs15_free_certificate(card_cert);        if (!parse_x509cert(blob, 0, x509cert))    {	plog("error in X.509 certificate");	free_x509cert(x509cert);	return FALSE;    }    cert->type = CERT_X509_SIGNATURE;    cert->u.x509 = x509cert;    plog("  loaded cert from smartcard (reader: %d, id: %s)", sc->reader, sc->id);    return TRUE;#else    plog("  warning: SMARTCARD support is deactivated in pluto/Makefile!");    return FALSE;#endif}/* * parse reader number and key id */smartcard_t*scx_parse_reader_id(const char *reader_id){    smartcard_t *sc = alloc_thing(smartcard_t, "smartcard");    char default_id[] = SCX_DEFAULT_ID;    int len = strlen(reader_id);    /*default values */    sc->reader    = SCX_DEFAULT_READER;    sc->id        = default_id;    sc->pin       = empty_chunk;    sc->valid     = FALSE;    sc->last_cert = empty_cert;    sc->last_load = 0;    sc->count     = 0;    sc->next      = NULL;    if (len > 0)    {	int reader_len = len;	err_t ugh = NULL;	unsigned long ul;	char *p;	/* look for colon separator*/	p = strchr(reader_id, ':');	if (p != NULL)	{	    int id_len = len - (p + 1 - reader_id);	    reader_len -= (1 + id_len);	    if (id_len > 0)	/* we have an ID */		sc->id = p + 1;	}	if (reader_len > 0)	{	    /* we have an id */	    ugh = atoul(reader_id, reader_len, 10, &ul);	    if (ugh == NULL)		sc->reader = ul;	    else		plog("error in smartcard reader number: %s", ugh);	}    }    /* unshare the id string */    sc->id = clone_str(sc->id, "key id");    return sc;}/* * Verify pin on card */boolscx_verify_pin(smartcard_t *sc UNUSED){#ifdef SMARTCARD    int r;    struct sc_pkcs15_object *key, *pin;    struct sc_pkcs15_id id;    sc->valid = FALSE;    if (sc->pin.ptr == NULL)    {	plog("unable to verify without PIN");	return FALSE;    }    /* establish context */    if (!scx_establish_context(sc->reader))    {	plog("unable to establish context with reader: %s"	    , sc_strerror(r));	return FALSE;    }    /* convert id-string to pkcs15-id */    sc_pkcs15_hex_string_to_id(sc->id, &id);    /* get private key by id */    r = sc_pkcs15_find_prkey_by_id(p15card, &id, &key);    if (r < 0)    {	plog("unable to find private key with id %s: %s"	    , sc->id, sc_strerror(r));	scx_release_context();	return FALSE;    }    /* get pin information by id */    r = sc_pkcs15_find_pin_by_auth_id(p15card, &key->auth_id, &pin);    if (r)    {	plog("unable to find PIN code for private key: %s"	    , sc_strerror(r));	scx_release_context();	return FALSE;    }    /* verify pin */    sc->valid = sc_pkcs15_verify_pin(p15card	    , (struct sc_pkcs15_pin_info *) pin->data	    , sc->pin.ptr, sc->pin.len) == 0;    scx_release_context();    DBG(DBG_CONTROL | DBG_CRYPT,	DBG_log("PIN code %s", sc->valid ? "correct":"incorrect")    );#else    sc->valid = FALSE;#endif    return sc->valid;}/* * Sign hash on smartcard */boolscx_sign_hash(smartcard_t *sc UNUSED	      , const u_char *in UNUSED	      , size_t inlen UNUSED	      , u_char *out UNUSED	      , size_t outlen UNUSED){#ifdef SMARTCARD    int r;    struct sc_pkcs15_object *key, *pin;    struct sc_pkcs15_id id;    if ((p15card == NULL) || (card == NULL))    {	plog("not connected to card!");	return FALSE;    }    if (sc->pin.ptr == NULL)    {	plog("unable to sign without PIN!");	return FALSE;    }    /* convert id-string to pkcs15-id */    sc_pkcs15_hex_string_to_id(sc->id, &id);    /* get private key by id */    r = sc_pkcs15_find_prkey_by_id(p15card, &id, &key);    if (r < 0)    {	plog("unable to find private key '%s': %s", sc->id, sc_strerror(r));	return FALSE;    }    /* get pin information by id */    r = sc_pkcs15_find_pin_by_auth_id(p15card, &key->auth_id, &pin);    if (r)    {	plog("unable to find PIN code for private key: %s", sc_strerror(r));	return FALSE;    }    /* verify pin with pin information */    r= sc_pkcs15_verify_pin(p15card, (struct sc_pkcs15_pin_info *) pin->data	, sc->pin.ptr, sc->pin.len);    if (r)    {	plog("PIN code verification failed: %s", sc_strerror(r));	return FALSE;    }    DBG(DBG_CONTROL | DBG_CRYPT,	DBG_log("PIN code correct")    )    /* sign on card */    r = sc_pkcs15_compute_signature(p15card, key, SC_ALGORITHM_RSA_PAD_PKCS1	, in, inlen, out, outlen);    if (r < 0)    {	plog("compute signature failed: %s", sc_strerror(r));	return FALSE;    }    return TRUE;#else    return FALSE;#endif}/* * get length of RSA key in bits */size_tscx_get_keylength(smartcard_t *sc UNUSED){#ifdef SMARTCARD    int r;    struct sc_pkcs15_id id;    struct sc_pkcs15_object *key;    if ((p15card == NULL) || (card == NULL))    {	plog("not connected to card!");	return 0;    }    /* convert id-string to pkcs15-id */    sc_pkcs15_hex_string_to_id(sc->id, &id);    /* get private key by id */    r = sc_pkcs15_find_prkey_by_id(p15card, &id, &key);    if (r < 0)    {	plog("unable to find private key '%s': %s", sc->id, sc_strerror(r));	return 0;    }    return ((struct sc_pkcs15_prkey_info *) key->data)->modulus_length;#else    return 0;#endif}/* * prompt for pin and verify it */boolscx_get_pin(smartcard_t *sc, int whackfd){#ifdef SMARTCARD    char pin[BUF_LEN];    int i, n;    whack_log(RC_ENTERSECRET, "need PIN for reader: %d, id: %s"	, sc->reader, sc->id);    for (i = 0; i < SCX_MAX_PIN_TRIALS; i++)    {	if (i > 0)	    whack_log(RC_ENTERSECRET, "invalid PIN, please try again");	n = read(whackfd, pin, BUF_LEN);	if (n == -1)	{	    whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");	    return FALSE;	}	if (strlen(pin) == 0)	{	    whack_log(RC_LOG_SERIOUS, "no PIN entered, aborted");	    return FALSE;	}	sc->pin.ptr = pin;	sc->pin.len = strlen(pin);	/* verify the pin */	if (scx_verify_pin(sc))	{	    clonetochunk(sc->pin, pin, strlen(pin), "pin");	    break;	}	/* wrong pin - we try another round */	sc->pin = empty_chunk;    }    if (sc->valid)	whack_log(RC_SUCCESS, "valid PIN");    else	whack_log(RC_LOG_SERIOUS, "invalid PIN, too many trials");#else    sc->valid = FALSE;    whack_log(RC_LOG_SERIOUS, "SMARTCARD support is deactivated in pluto/Makefile!");#endif    return sc->valid;}/* * free the pin code */voidscx_free_pin(chunk_t *pin){    if (pin->ptr != NULL)    {	pfree(pin->ptr);	*pin = empty_chunk;    }}/* * frees a smartcard record */voidscx_free(smartcard_t *sc){    if (sc != NULL)    {	pfreeany(sc->id);	scx_free_pin(&sc->pin);	pfree(sc);    }}/*  release of a smartcard record decreases the count by one "  the record is freed when the counter reaches zero */voidscx_release(smartcard_t *sc){    if (sc != NULL && --sc->count == 0)    {	smartcard_t **pp = &smartcards;	while (*pp != sc)	    pp = &(*pp)->next;	lock_certs_and_keys("scx_release");        *pp = sc->next;	unlock_certs_and_keys("scx_release");	release_cert(sc->last_cert);	scx_free(sc);    }}/* *  compare two smartcard records by comparing their readers and ids */static boolscx_same(smartcard_t *a, smartcard_t *b){    return a->reader == b->reader && streq(a->id, b->id);}/*  for each link pointing to the smartcard record "  increase the count by one */voidscx_share(smartcard_t *sc){    if (sc != NULL) 	sc->count++;}/* *  adds a smartcard record to the chained list */smartcard_t*scx_add(smartcard_t *smartcard){    smartcard_t *sc = smartcards;    while (sc != NULL)    {	if (scx_same(sc, smartcard)) /* already in chain, free smartcard record */	{	    scx_free(smartcard);	    return sc;	}	sc = sc->next;    }    /* insert new smartcard record at the root of the chain */    lock_certs_and_keys("scx_add");    smartcard->next = smartcards;    smartcards = smartcard;    unlock_certs_and_keys("scx_add");    return smartcard;}/* * get the smartcard that belongs to an X.509 certificate */smartcard_t*scx_get(x509cert_t *cert){    smartcard_t *sc = smartcards;    while (sc != NULL)    {	if (sc->last_cert.u.x509 == cert)	    return sc;	sc = sc->next;    }    return NULL;}/* *  list all smartcard info records in a chained list */voidscx_list(bool utc){    smartcard_t *sc = smartcards;    char tbuf[TIMETOA_BUF];    if (sc != NULL)    {	whack_log(RC_COMMENT, " ");	whack_log(RC_COMMENT, "List of Smartcard Records:");	whack_log(RC_COMMENT, " ");    }    while (sc != NULL)    {	whack_log(RC_COMMENT, "%s, count: %d", timetoa(&sc->last_load, utc, tbuf, sizeof(tbuf))	    , sc->count);	whack_log(RC_COMMENT, "       reader: %d, id: %s, has %s pin", sc->reader, sc->id	    , (sc->pin.ptr == NULL)? "no" : ((sc->valid)? "valid" : "invalid"));	sc = sc->next;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -