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

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.10    ! jakob      27: RCSID("$OpenBSD: scard.c,v 1.9 2001/07/31 08:41:10 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);
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:
                     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:
                     98: static int
                     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:
                    118: static int
                    119: sc_read_pubkey(Key * k)
                    120: {
1.4       markus    121:        u_char buf[2], *n;
                    122:        char *p;
1.8       jakob     123:        int len, sw, status;
1.1       markus    124:
1.4       markus    125:        len = sw = 0;
1.1       markus    126:
1.8       jakob     127:        if (sc_fd < 0) {
                    128:                status = sc_init();
                    129:                if (status < 0 )
                    130:                        return status;
                    131:        }
1.5       markus    132:
1.1       markus    133:        /* get key size */
1.4       markus    134:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
                    135:             sizeof(buf), buf, &sw);
                    136:        if (!sectok_swOK(sw)) {
                    137:                error("could not obtain key length: %s", sectok_get_sw(sw));
1.5       markus    138:                sc_close();
1.4       markus    139:                return -1;
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));
                    150:                xfree(n);
                    151:                return -1;
1.1       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");
                    157:                xfree(n);
1.5       markus    158:                sc_close();
1.4       markus    159:                return -1;
                    160:        }
                    161:        xfree(n);
1.1       markus    162:
                    163:        /* currently the java applet just stores 'n' */
1.4       markus    164:        if (!BN_set_word(k->rsa->e, 35)) {
                    165:                error("c_read_pubkey: BN_set_word(e, 35) failed");
                    166:                return -1;
                    167:        }
1.1       markus    168:
                    169:        p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
                    170:        debug("fingerprint %d %s", key_size(k), p);
                    171:        xfree(p);
                    172:
                    173:        return 0;
                    174: }
                    175:
                    176: /* private key operations */
                    177:
                    178: static int
1.4       markus    179: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    180: {
1.4       markus    181:        u_char *padded = NULL;
1.8       jakob     182:        int sw, len, olen, status;
1.1       markus    183:
                    184:        debug("sc_private_decrypt called");
                    185:
1.4       markus    186:        olen = len = sw = 0;
1.8       jakob     187:        if (sc_fd < 0) {
                    188:                status = sc_init();
                    189:                if (status < 0 )
1.5       markus    190:                        goto err;
1.8       jakob     191:        }
1.4       markus    192:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    193:                goto err;
                    194:
1.4       markus    195:        len = BN_num_bytes(rsa->n);
                    196:        padded = xmalloc(len);
1.1       markus    197:
1.4       markus    198:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
                    199:        if (!sectok_swOK(sw)) {
                    200:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    201:                    sectok_get_sw(sw));
1.5       markus    202:                sc_close();
1.1       markus    203:                goto err;
                    204:        }
1.4       markus    205:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
                    206:             len, padded, &sw);
                    207:        if (!sectok_swOK(sw)) {
                    208:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    209:                    sectok_get_sw(sw));
1.5       markus    210:                sc_close();
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.8       jakob     218:        return (olen >= 0 ? olen : status);
1.1       markus    219: }
                    220:
                    221: static int
1.4       markus    222: sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    223: {
1.4       markus    224:        u_char *padded = NULL;
1.8       jakob     225:        int sw, len, status;
1.1       markus    226:
1.4       markus    227:        len = sw = 0;
1.8       jakob     228:        if (sc_fd < 0) {
                    229:                status = sc_init();
                    230:                if (status < 0 )
1.5       markus    231:                        goto err;
1.8       jakob     232:        }
1.4       markus    233:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    234:                goto err;
                    235:
1.3       markus    236:        debug("sc_private_encrypt called");
1.4       markus    237:        len = BN_num_bytes(rsa->n);
                    238:        padded = xmalloc(len);
                    239:
                    240:        if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
1.1       markus    241:                error("RSA_padding_add_PKCS1_type_1 failed");
                    242:                goto err;
                    243:        }
1.4       markus    244:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
                    245:        if (!sectok_swOK(sw)) {
                    246:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    247:                    sectok_get_sw(sw));
1.5       markus    248:                sc_close();
1.4       markus    249:                goto err;
                    250:        }
                    251:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
                    252:             len, to, &sw);
                    253:        if (!sectok_swOK(sw)) {
                    254:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    255:                    sectok_get_sw(sw));
1.5       markus    256:                sc_close();
1.4       markus    257:                goto err;
1.1       markus    258:        }
                    259: err:
                    260:        if (padded)
                    261:                xfree(padded);
1.8       jakob     262:        return (len >= 0 ? len : status);
1.1       markus    263: }
                    264:
                    265: /* engine for overloading private key operations */
                    266:
                    267: static ENGINE *smart_engine = NULL;
                    268: static RSA_METHOD smart_rsa =
                    269: {
1.4       markus    270:        "sectok",
                    271:        NULL,
                    272:        NULL,
                    273:        NULL,
                    274:        NULL,
                    275:        NULL,
                    276:        NULL,
                    277:        NULL,
                    278:        NULL,
                    279:        0,
                    280:        NULL,
1.1       markus    281: };
                    282:
                    283: ENGINE *
1.2       itojun    284: sc_get_engine(void)
1.1       markus    285: {
                    286:        RSA_METHOD *def;
                    287:
                    288:        def = RSA_get_default_openssl_method();
                    289:
                    290:        /* overload */
                    291:        smart_rsa.rsa_priv_enc  = sc_private_encrypt;
                    292:        smart_rsa.rsa_priv_dec  = sc_private_decrypt;
                    293:
                    294:        /* just use the OpenSSL version */
1.4       markus    295:        smart_rsa.rsa_pub_enc   = def->rsa_pub_enc;
                    296:        smart_rsa.rsa_pub_dec   = def->rsa_pub_dec;
1.1       markus    297:        smart_rsa.rsa_mod_exp   = def->rsa_mod_exp;
                    298:        smart_rsa.bn_mod_exp    = def->bn_mod_exp;
                    299:        smart_rsa.init          = def->init;
                    300:        smart_rsa.finish        = def->finish;
                    301:        smart_rsa.flags         = def->flags;
                    302:        smart_rsa.app_data      = def->app_data;
                    303:        smart_rsa.rsa_sign      = def->rsa_sign;
                    304:        smart_rsa.rsa_verify    = def->rsa_verify;
                    305:
                    306:        smart_engine = ENGINE_new();
                    307:
1.4       markus    308:        ENGINE_set_id(smart_engine, "sectok");
                    309:        ENGINE_set_name(smart_engine, "libsectok");
1.1       markus    310:        ENGINE_set_RSA(smart_engine, &smart_rsa);
                    311:        ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
                    312:        ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
                    313:        ENGINE_set_RAND(smart_engine, RAND_SSLeay());
                    314:        ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
                    315:
                    316:        return smart_engine;
                    317: }
                    318:
1.5       markus    319: void
                    320: sc_close(void)
                    321: {
                    322:        if (sc_fd >= 0) {
                    323:                sectok_close(sc_fd);
                    324:                sc_fd = -1;
                    325:        }
                    326: }
                    327:
1.1       markus    328: Key *
1.5       markus    329: sc_get_key(int num)
1.1       markus    330: {
                    331:        Key *k;
1.9       jakob     332:        int status;
1.1       markus    333:
1.5       markus    334:        sc_reader_num = num;
1.1       markus    335:        k = key_new(KEY_RSA);
                    336:        if (k == NULL) {
                    337:                return NULL;
                    338:        }
1.9       jakob     339:        status = sc_read_pubkey(k);
                    340:        if (status == SCARD_ERROR_NOCARD) {
                    341:                key_free(k);
                    342:                return NULL;
                    343:        }
                    344:        if (status < 0 ) {
1.1       markus    345:                error("sc_read_pubkey failed");
                    346:                key_free(k);
                    347:                return NULL;
                    348:        }
                    349:        return k;
1.5       markus    350:        sc_close();
1.1       markus    351: }
                    352: #endif