[BACK]Return to scard.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/scard.c, Revision 1.15.2.1

1.1       markus      1: /*
                      2:  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
                      3:  *
                      4:  * Redistribution and use in source and binary forms, with or without
                      5:  * modification, are permitted provided that the following conditions
                      6:  * are met:
                      7:  * 1. Redistributions of source code must retain the above copyright
                      8:  *    notice, this list of conditions and the following disclaimer.
                      9:  * 2. Redistributions in binary form must reproduce the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer in the
                     11:  *    documentation and/or other materials provided with the distribution.
                     12:  *
                     13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     14:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     15:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     16:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     17:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     18:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     19:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     20:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     21:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     22:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     23:  */
                     24:
                     25: #ifdef SMARTCARD
                     26: #include "includes.h"
1.15.2.1! jason      27: RCSID("$OpenBSD: scard.c,v 1.17 2001/12/27 18:22:16 markus Exp $");
1.1       markus     28:
                     29: #include <openssl/engine.h>
                     30: #include <sectok.h>
                     31:
                     32: #include "key.h"
                     33: #include "log.h"
                     34: #include "xmalloc.h"
                     35: #include "scard.h"
                     36:
                     37: #define CLA_SSH 0x05
                     38: #define INS_DECRYPT 0x10
                     39: #define INS_GET_KEYLENGTH 0x20
                     40: #define INS_GET_PUBKEY 0x30
                     41: #define INS_GET_RESPONSE 0xc0
                     42:
                     43: #define MAX_BUF_SIZE 256
                     44:
                     45: static int sc_fd = -1;
1.11      markus     46: static char *sc_reader_id = NULL;
1.1       markus     47: static int cla = 0x00; /* class */
                     48:
                     49: /* interface to libsectok */
                     50:
1.15.2.1! jason      51: static int
1.5       markus     52: sc_open(void)
1.1       markus     53: {
1.4       markus     54:        int sw;
1.1       markus     55:
                     56:        if (sc_fd >= 0)
                     57:                return sc_fd;
                     58:
1.11      markus     59:        sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
1.1       markus     60:        if (sc_fd < 0) {
1.5       markus     61:                error("sectok_open failed: %s", sectok_get_sw(sw));
1.8       jakob      62:                return SCARD_ERROR_FAIL;
                     63:        }
                     64:        if (! sectok_cardpresent(sc_fd)) {
1.11      markus     65:                debug("smartcard in reader %s not present, skipping",
                     66:                    sc_reader_id);
1.10      jakob      67:                sc_close();
1.8       jakob      68:                return SCARD_ERROR_NOCARD;
1.1       markus     69:        }
1.7       rees       70:        if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
1.4       markus     71:                error("sectok_reset failed: %s", sectok_get_sw(sw));
1.1       markus     72:                sc_fd = -1;
1.8       jakob      73:                return SCARD_ERROR_FAIL;
1.1       markus     74:        }
1.7       rees       75:        if ((cla = cyberflex_inq_class(sc_fd)) < 0)
                     76:                cla = 0;
1.5       markus     77:
1.4       markus     78:        debug("sc_open ok %d", sc_fd);
1.1       markus     79:        return sc_fd;
                     80: }
                     81:
1.15.2.1! jason      82: static int
1.4       markus     83: sc_enable_applet(void)
1.1       markus     84: {
1.7       rees       85:        static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
                     86:        int sw = 0;
1.1       markus     87:
1.7       rees       88:        /* select applet id */
                     89:        sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
1.4       markus     90:        if (!sectok_swOK(sw)) {
                     91:                error("sectok_apdu failed: %s", sectok_get_sw(sw));
1.5       markus     92:                sc_close();
                     93:                return -1;
                     94:        }
                     95:        return 0;
                     96: }
                     97:
1.15.2.1! jason      98: static int
1.5       markus     99: sc_init(void)
                    100: {
1.8       jakob     101:        int status;
                    102:
                    103:        status = sc_open();
                    104:        if (status == SCARD_ERROR_NOCARD) {
                    105:                return SCARD_ERROR_NOCARD;
                    106:        }
                    107:        if (status < 0 ) {
1.5       markus    108:                error("sc_open failed");
1.8       jakob     109:                return status;
1.5       markus    110:        }
                    111:        if (sc_enable_applet() < 0) {
                    112:                error("sc_enable_applet failed");
1.8       jakob     113:                return SCARD_ERROR_APPLET;
1.1       markus    114:        }
                    115:        return 0;
                    116: }
                    117:
1.15.2.1! jason     118: static int
1.1       markus    119: sc_read_pubkey(Key * k)
                    120: {
1.4       markus    121:        u_char buf[2], *n;
                    122:        char *p;
1.14      markus    123:        int len, sw, status = -1;
1.1       markus    124:
1.4       markus    125:        len = sw = 0;
1.15      djm       126:        n = NULL;
1.1       markus    127:
1.8       jakob     128:        if (sc_fd < 0) {
                    129:                status = sc_init();
                    130:                if (status < 0 )
1.14      markus    131:                        goto err;
1.8       jakob     132:        }
1.5       markus    133:
1.1       markus    134:        /* get key size */
1.4       markus    135:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
1.15.2.1! jason     136:            sizeof(buf), buf, &sw);
1.4       markus    137:        if (!sectok_swOK(sw)) {
                    138:                error("could not obtain key length: %s", sectok_get_sw(sw));
1.14      markus    139:                goto err;
1.1       markus    140:        }
                    141:        len = (buf[0] << 8) | buf[1];
                    142:        len /= 8;
1.4       markus    143:        debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
1.1       markus    144:
1.4       markus    145:        n = xmalloc(len);
1.1       markus    146:        /* get n */
1.4       markus    147:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
                    148:        if (!sectok_swOK(sw)) {
                    149:                error("could not obtain public key: %s", sectok_get_sw(sw));
1.14      markus    150:                goto err;
1.1       markus    151:        }
1.14      markus    152:
1.4       markus    153:        debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
                    154:
                    155:        if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
                    156:                error("c_read_pubkey: BN_bin2bn failed");
1.14      markus    157:                goto err;
1.4       markus    158:        }
1.1       markus    159:
                    160:        /* currently the java applet just stores 'n' */
1.4       markus    161:        if (!BN_set_word(k->rsa->e, 35)) {
                    162:                error("c_read_pubkey: BN_set_word(e, 35) failed");
1.14      markus    163:                goto err;
1.4       markus    164:        }
1.1       markus    165:
1.14      markus    166:        status = 0;
1.1       markus    167:        p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
                    168:        debug("fingerprint %d %s", key_size(k), p);
                    169:        xfree(p);
                    170:
1.14      markus    171: err:
                    172:        if (n != NULL)
                    173:                xfree(n);
                    174:        sc_close();
                    175:        return status;
1.1       markus    176: }
                    177:
                    178: /* private key operations */
                    179:
                    180: static int
1.4       markus    181: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    182: {
1.4       markus    183:        u_char *padded = NULL;
1.14      markus    184:        int sw, len, olen, status = -1;
1.1       markus    185:
                    186:        debug("sc_private_decrypt called");
                    187:
1.4       markus    188:        olen = len = sw = 0;
1.8       jakob     189:        if (sc_fd < 0) {
                    190:                status = sc_init();
                    191:                if (status < 0 )
1.5       markus    192:                        goto err;
1.8       jakob     193:        }
1.4       markus    194:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    195:                goto err;
                    196:
1.4       markus    197:        len = BN_num_bytes(rsa->n);
                    198:        padded = xmalloc(len);
1.1       markus    199:
1.4       markus    200:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
                    201:        if (!sectok_swOK(sw)) {
                    202:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    203:                    sectok_get_sw(sw));
1.1       markus    204:                goto err;
                    205:        }
1.4       markus    206:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
1.15.2.1! jason     207:            len, padded, &sw);
1.4       markus    208:        if (!sectok_swOK(sw)) {
                    209:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    210:                    sectok_get_sw(sw));
1.1       markus    211:                goto err;
                    212:        }
1.4       markus    213:        olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
                    214:            len);
1.1       markus    215: err:
                    216:        if (padded)
                    217:                xfree(padded);
1.14      markus    218:        sc_close();
1.8       jakob     219:        return (olen >= 0 ? olen : status);
1.1       markus    220: }
                    221:
                    222: static int
1.4       markus    223: sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    224: {
1.4       markus    225:        u_char *padded = NULL;
1.14      markus    226:        int sw, len, status = -1;
1.1       markus    227:
1.4       markus    228:        len = sw = 0;
1.8       jakob     229:        if (sc_fd < 0) {
                    230:                status = sc_init();
                    231:                if (status < 0 )
1.5       markus    232:                        goto err;
1.8       jakob     233:        }
1.4       markus    234:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    235:                goto err;
                    236:
1.3       markus    237:        debug("sc_private_encrypt called");
1.4       markus    238:        len = BN_num_bytes(rsa->n);
                    239:        padded = xmalloc(len);
                    240:
                    241:        if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
1.1       markus    242:                error("RSA_padding_add_PKCS1_type_1 failed");
                    243:                goto err;
                    244:        }
1.4       markus    245:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
                    246:        if (!sectok_swOK(sw)) {
                    247:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    248:                    sectok_get_sw(sw));
                    249:                goto err;
                    250:        }
                    251:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
1.15.2.1! jason     252:            len, to, &sw);
1.4       markus    253:        if (!sectok_swOK(sw)) {
                    254:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    255:                    sectok_get_sw(sw));
                    256:                goto err;
1.1       markus    257:        }
                    258: err:
                    259:        if (padded)
                    260:                xfree(padded);
1.14      markus    261:        sc_close();
1.8       jakob     262:        return (len >= 0 ? len : status);
1.1       markus    263: }
                    264:
1.12      markus    265: /* called on free */
                    266:
                    267: static int (*orig_finish)(RSA *rsa) = NULL;
                    268:
                    269: static int
                    270: sc_finish(RSA *rsa)
                    271: {
                    272:        if (orig_finish)
                    273:                orig_finish(rsa);
                    274:        sc_close();
                    275:        return 1;
                    276: }
                    277:
                    278:
1.1       markus    279: /* engine for overloading private key operations */
                    280:
                    281: static ENGINE *smart_engine = NULL;
                    282: static RSA_METHOD smart_rsa =
                    283: {
1.4       markus    284:        "sectok",
                    285:        NULL,
                    286:        NULL,
                    287:        NULL,
                    288:        NULL,
                    289:        NULL,
                    290:        NULL,
                    291:        NULL,
                    292:        NULL,
                    293:        0,
                    294:        NULL,
1.1       markus    295: };
                    296:
                    297: ENGINE *
1.2       itojun    298: sc_get_engine(void)
1.1       markus    299: {
                    300:        RSA_METHOD *def;
                    301:
                    302:        def = RSA_get_default_openssl_method();
                    303:
                    304:        /* overload */
                    305:        smart_rsa.rsa_priv_enc  = sc_private_encrypt;
                    306:        smart_rsa.rsa_priv_dec  = sc_private_decrypt;
                    307:
1.12      markus    308:        /* save original */
                    309:        orig_finish             = def->finish;
                    310:        smart_rsa.finish        = sc_finish;
                    311:
1.1       markus    312:        /* just use the OpenSSL version */
1.4       markus    313:        smart_rsa.rsa_pub_enc   = def->rsa_pub_enc;
                    314:        smart_rsa.rsa_pub_dec   = def->rsa_pub_dec;
1.1       markus    315:        smart_rsa.rsa_mod_exp   = def->rsa_mod_exp;
                    316:        smart_rsa.bn_mod_exp    = def->bn_mod_exp;
                    317:        smart_rsa.init          = def->init;
                    318:        smart_rsa.flags         = def->flags;
                    319:        smart_rsa.app_data      = def->app_data;
                    320:        smart_rsa.rsa_sign      = def->rsa_sign;
                    321:        smart_rsa.rsa_verify    = def->rsa_verify;
                    322:
1.15.2.1! jason     323:        if ((smart_engine = ENGINE_new()) == NULL)
        !           324:                fatal("ENGINE_new failed");
1.1       markus    325:
1.4       markus    326:        ENGINE_set_id(smart_engine, "sectok");
                    327:        ENGINE_set_name(smart_engine, "libsectok");
1.1       markus    328:        ENGINE_set_RSA(smart_engine, &smart_rsa);
                    329:        ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
                    330:        ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
                    331:        ENGINE_set_RAND(smart_engine, RAND_SSLeay());
                    332:        ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
                    333:
                    334:        return smart_engine;
                    335: }
                    336:
1.5       markus    337: void
                    338: sc_close(void)
                    339: {
                    340:        if (sc_fd >= 0) {
                    341:                sectok_close(sc_fd);
                    342:                sc_fd = -1;
                    343:        }
                    344: }
                    345:
1.1       markus    346: Key *
1.11      markus    347: sc_get_key(const char *id)
1.1       markus    348: {
                    349:        Key *k;
1.9       jakob     350:        int status;
1.1       markus    351:
1.11      markus    352:        if (sc_reader_id != NULL)
                    353:                xfree(sc_reader_id);
                    354:        sc_reader_id = xstrdup(id);
                    355:
1.1       markus    356:        k = key_new(KEY_RSA);
                    357:        if (k == NULL) {
                    358:                return NULL;
                    359:        }
1.9       jakob     360:        status = sc_read_pubkey(k);
                    361:        if (status == SCARD_ERROR_NOCARD) {
                    362:                key_free(k);
                    363:                return NULL;
                    364:        }
                    365:        if (status < 0 ) {
1.1       markus    366:                error("sc_read_pubkey failed");
                    367:                key_free(k);
                    368:                return NULL;
                    369:        }
                    370:        return k;
                    371: }
1.13      jakob     372: #endif /* SMARTCARD */