[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.9

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.9     ! jakob      27: RCSID("$OpenBSD: scard.c,v 1.8 2001/07/30 16:06:07 jakob 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.5       markus     46: static int sc_reader_num = -1;
1.1       markus     47: static int cla = 0x00; /* class */
                     48:
                     49: /* interface to libsectok */
                     50:
                     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.8       jakob      59:        sc_fd = sectok_open(sc_reader_num, 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.9     ! jakob      65:                debug("smartcard in reader %d not present, skipping",
1.8       jakob      66:                    sc_reader_num);
                     67:                return SCARD_ERROR_NOCARD;
1.1       markus     68:        }
1.7       rees       69:        if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
1.4       markus     70:                error("sectok_reset failed: %s", sectok_get_sw(sw));
1.1       markus     71:                sc_fd = -1;
1.8       jakob      72:                return SCARD_ERROR_FAIL;
1.1       markus     73:        }
1.7       rees       74:        if ((cla = cyberflex_inq_class(sc_fd)) < 0)
                     75:                cla = 0;
1.5       markus     76:
1.4       markus     77:        debug("sc_open ok %d", sc_fd);
1.1       markus     78:        return sc_fd;
                     79: }
                     80:
                     81: static int
1.4       markus     82: sc_enable_applet(void)
1.1       markus     83: {
1.7       rees       84:        static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
                     85:        int sw = 0;
1.1       markus     86:
1.7       rees       87:        /* select applet id */
                     88:        sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
1.4       markus     89:        if (!sectok_swOK(sw)) {
                     90:                error("sectok_apdu failed: %s", sectok_get_sw(sw));
1.5       markus     91:                sc_close();
                     92:                return -1;
                     93:        }
                     94:        return 0;
                     95: }
                     96:
                     97: static int
                     98: sc_init(void)
                     99: {
1.8       jakob     100:        int status;
                    101:
                    102:        status = sc_open();
                    103:        if (status == SCARD_ERROR_NOCARD) {
                    104:                return SCARD_ERROR_NOCARD;
                    105:        }
                    106:        if (status < 0 ) {
1.5       markus    107:                error("sc_open failed");
1.8       jakob     108:                return status;
1.5       markus    109:        }
                    110:        if (sc_enable_applet() < 0) {
                    111:                error("sc_enable_applet failed");
1.8       jakob     112:                return SCARD_ERROR_APPLET;
1.1       markus    113:        }
                    114:        return 0;
                    115: }
                    116:
                    117: static int
                    118: sc_read_pubkey(Key * k)
                    119: {
1.4       markus    120:        u_char buf[2], *n;
                    121:        char *p;
1.8       jakob     122:        int len, sw, status;
1.1       markus    123:
1.4       markus    124:        len = sw = 0;
1.1       markus    125:
1.8       jakob     126:        if (sc_fd < 0) {
                    127:                status = sc_init();
                    128:                if (status < 0 )
                    129:                        return status;
                    130:        }
1.5       markus    131:
1.1       markus    132:        /* get key size */
1.4       markus    133:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
                    134:             sizeof(buf), buf, &sw);
                    135:        if (!sectok_swOK(sw)) {
                    136:                error("could not obtain key length: %s", sectok_get_sw(sw));
1.5       markus    137:                sc_close();
1.4       markus    138:                return -1;
1.1       markus    139:        }
                    140:        len = (buf[0] << 8) | buf[1];
                    141:        len /= 8;
1.4       markus    142:        debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
1.1       markus    143:
1.4       markus    144:        n = xmalloc(len);
1.1       markus    145:        /* get n */
1.4       markus    146:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
                    147:        if (!sectok_swOK(sw)) {
                    148:                error("could not obtain public key: %s", sectok_get_sw(sw));
                    149:                xfree(n);
                    150:                return -1;
1.1       markus    151:        }
1.4       markus    152:        debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
                    153:
                    154:        if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
                    155:                error("c_read_pubkey: BN_bin2bn failed");
                    156:                xfree(n);
1.5       markus    157:                sc_close();
1.4       markus    158:                return -1;
                    159:        }
                    160:        xfree(n);
1.1       markus    161:
                    162:        /* currently the java applet just stores 'n' */
1.4       markus    163:        if (!BN_set_word(k->rsa->e, 35)) {
                    164:                error("c_read_pubkey: BN_set_word(e, 35) failed");
                    165:                return -1;
                    166:        }
1.1       markus    167:
                    168:        p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
                    169:        debug("fingerprint %d %s", key_size(k), p);
                    170:        xfree(p);
                    171:
                    172:        return 0;
                    173: }
                    174:
                    175: /* private key operations */
                    176:
                    177: static int
1.4       markus    178: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    179: {
1.4       markus    180:        u_char *padded = NULL;
1.8       jakob     181:        int sw, len, olen, status;
1.1       markus    182:
                    183:        debug("sc_private_decrypt called");
                    184:
1.4       markus    185:        olen = len = sw = 0;
1.8       jakob     186:        if (sc_fd < 0) {
                    187:                status = sc_init();
                    188:                if (status < 0 )
1.5       markus    189:                        goto err;
1.8       jakob     190:        }
1.4       markus    191:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    192:                goto err;
                    193:
1.4       markus    194:        len = BN_num_bytes(rsa->n);
                    195:        padded = xmalloc(len);
1.1       markus    196:
1.4       markus    197:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
                    198:        if (!sectok_swOK(sw)) {
                    199:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    200:                    sectok_get_sw(sw));
1.5       markus    201:                sc_close();
1.1       markus    202:                goto err;
                    203:        }
1.4       markus    204:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
                    205:             len, padded, &sw);
                    206:        if (!sectok_swOK(sw)) {
                    207:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    208:                    sectok_get_sw(sw));
1.5       markus    209:                sc_close();
1.1       markus    210:                goto err;
                    211:        }
1.4       markus    212:        olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
                    213:            len);
1.1       markus    214: err:
                    215:        if (padded)
                    216:                xfree(padded);
1.8       jakob     217:        return (olen >= 0 ? olen : status);
1.1       markus    218: }
                    219:
                    220: static int
1.4       markus    221: sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    222: {
1.4       markus    223:        u_char *padded = NULL;
1.8       jakob     224:        int sw, len, status;
1.1       markus    225:
1.4       markus    226:        len = sw = 0;
1.8       jakob     227:        if (sc_fd < 0) {
                    228:                status = sc_init();
                    229:                if (status < 0 )
1.5       markus    230:                        goto err;
1.8       jakob     231:        }
1.4       markus    232:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    233:                goto err;
                    234:
1.3       markus    235:        debug("sc_private_encrypt called");
1.4       markus    236:        len = BN_num_bytes(rsa->n);
                    237:        padded = xmalloc(len);
                    238:
                    239:        if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
1.1       markus    240:                error("RSA_padding_add_PKCS1_type_1 failed");
                    241:                goto err;
                    242:        }
1.4       markus    243:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
                    244:        if (!sectok_swOK(sw)) {
                    245:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    246:                    sectok_get_sw(sw));
1.5       markus    247:                sc_close();
1.4       markus    248:                goto err;
                    249:        }
                    250:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
                    251:             len, to, &sw);
                    252:        if (!sectok_swOK(sw)) {
                    253:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    254:                    sectok_get_sw(sw));
1.5       markus    255:                sc_close();
1.4       markus    256:                goto err;
1.1       markus    257:        }
                    258: err:
                    259:        if (padded)
                    260:                xfree(padded);
1.8       jakob     261:        return (len >= 0 ? len : status);
1.1       markus    262: }
                    263:
                    264: /* engine for overloading private key operations */
                    265:
                    266: static ENGINE *smart_engine = NULL;
                    267: static RSA_METHOD smart_rsa =
                    268: {
1.4       markus    269:        "sectok",
                    270:        NULL,
                    271:        NULL,
                    272:        NULL,
                    273:        NULL,
                    274:        NULL,
                    275:        NULL,
                    276:        NULL,
                    277:        NULL,
                    278:        0,
                    279:        NULL,
1.1       markus    280: };
                    281:
                    282: ENGINE *
1.2       itojun    283: sc_get_engine(void)
1.1       markus    284: {
                    285:        RSA_METHOD *def;
                    286:
                    287:        def = RSA_get_default_openssl_method();
                    288:
                    289:        /* overload */
                    290:        smart_rsa.rsa_priv_enc  = sc_private_encrypt;
                    291:        smart_rsa.rsa_priv_dec  = sc_private_decrypt;
                    292:
                    293:        /* just use the OpenSSL version */
1.4       markus    294:        smart_rsa.rsa_pub_enc   = def->rsa_pub_enc;
                    295:        smart_rsa.rsa_pub_dec   = def->rsa_pub_dec;
1.1       markus    296:        smart_rsa.rsa_mod_exp   = def->rsa_mod_exp;
                    297:        smart_rsa.bn_mod_exp    = def->bn_mod_exp;
                    298:        smart_rsa.init          = def->init;
                    299:        smart_rsa.finish        = def->finish;
                    300:        smart_rsa.flags         = def->flags;
                    301:        smart_rsa.app_data      = def->app_data;
                    302:        smart_rsa.rsa_sign      = def->rsa_sign;
                    303:        smart_rsa.rsa_verify    = def->rsa_verify;
                    304:
                    305:        smart_engine = ENGINE_new();
                    306:
1.4       markus    307:        ENGINE_set_id(smart_engine, "sectok");
                    308:        ENGINE_set_name(smart_engine, "libsectok");
1.1       markus    309:        ENGINE_set_RSA(smart_engine, &smart_rsa);
                    310:        ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
                    311:        ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
                    312:        ENGINE_set_RAND(smart_engine, RAND_SSLeay());
                    313:        ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
                    314:
                    315:        return smart_engine;
                    316: }
                    317:
1.5       markus    318: void
                    319: sc_close(void)
                    320: {
                    321:        if (sc_fd >= 0) {
                    322:                sectok_close(sc_fd);
                    323:                sc_fd = -1;
                    324:        }
                    325: }
                    326:
1.1       markus    327: Key *
1.5       markus    328: sc_get_key(int num)
1.1       markus    329: {
                    330:        Key *k;
1.9     ! jakob     331:        int status;
1.1       markus    332:
1.5       markus    333:        sc_reader_num = num;
1.1       markus    334:        k = key_new(KEY_RSA);
                    335:        if (k == NULL) {
                    336:                return NULL;
                    337:        }
1.9     ! jakob     338:        status = sc_read_pubkey(k);
        !           339:        if (status == SCARD_ERROR_NOCARD) {
        !           340:                key_free(k);
        !           341:                return NULL;
        !           342:        }
        !           343:        if (status < 0 ) {
1.1       markus    344:                error("sc_read_pubkey failed");
                    345:                key_free(k);
                    346:                return NULL;
                    347:        }
                    348:        return k;
1.5       markus    349:        sc_close();
1.1       markus    350: }
                    351: #endif