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

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.5     ! markus     27: RCSID("$OpenBSD: scard.c,v 1.4 2001/07/02 22:40:17 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.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: {
                     54:        u_char atr[256];
1.4       markus     55:        int sw;
1.1       markus     56:
                     57:        if (sc_fd >= 0)
                     58:                return sc_fd;
                     59:
1.5     ! markus     60:        sc_fd = sectok_open(sc_reader_num, 0, &sw);
1.1       markus     61:        if (sc_fd < 0) {
1.5     ! markus     62:                error("sectok_open failed: %s", sectok_get_sw(sw));
        !            63:                return -1;
1.1       markus     64:        }
1.4       markus     65:        if (sectok_reset(sc_fd, 0, atr, &sw) <= 0) {
                     66:                error("sectok_reset failed: %s", sectok_get_sw(sw));
1.1       markus     67:                sc_fd = -1;
                     68:                return sc_fd;
                     69:        }
1.5     ! markus     70:
1.4       markus     71:        debug("sc_open ok %d", sc_fd);
1.1       markus     72:        return sc_fd;
                     73: }
                     74:
                     75: static int
1.4       markus     76: sc_enable_applet(void)
1.1       markus     77: {
1.4       markus     78:        u_char contID[2], aid[MAX_BUF_SIZE];
                     79:        int i, len, sw, aid_len;
1.1       markus     80:
1.4       markus     81:        len = sw = 0;
1.1       markus     82:        contID[0] = 0x77;
                     83:        contID[1] = 0x78;
                     84:
1.4       markus     85:        if (sectok_selectfile(sc_fd, cla, root_fid, &sw) < 0) {
                     86:                error("sectok_selectfile root_fid failed: %s",
                     87:                    sectok_get_sw(sw));
1.5     ! markus     88:                sc_close();
1.1       markus     89:                return -1;
                     90:        }
1.4       markus     91:        if (sectok_selectfile(sc_fd, cla, contID, &sw) < 0) {
                     92:                error("sectok_selectfile failed: %s", sectok_get_sw(sw));
1.5     ! markus     93:                sc_close();
1.4       markus     94:                return -1;
                     95:        }
                     96:        /* send appled id */
                     97:        for (i = 0; i < sizeof(aid); i++)
                     98:                aid[i] = 0x77;
                     99:        aid_len = 5;
                    100:        sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, aid_len, aid, 0, NULL, &sw);
                    101:        if (!sectok_swOK(sw)) {
                    102:                error("sectok_apdu failed: %s", sectok_get_sw(sw));
1.5     ! markus    103:                sc_close();
        !           104:                return -1;
        !           105:        }
        !           106:        return 0;
        !           107: }
        !           108:
        !           109: static int
        !           110: sc_init(void)
        !           111: {
        !           112:        if (sc_open() < 0) {
        !           113:                error("sc_open failed");
        !           114:                return -1;
        !           115:        }
        !           116:        if (sc_enable_applet() < 0) {
        !           117:                error("sc_enable_applet failed");
1.1       markus    118:                return -1;
                    119:        }
                    120:        return 0;
                    121: }
                    122:
                    123: static int
                    124: sc_read_pubkey(Key * k)
                    125: {
1.4       markus    126:        u_char buf[2], *n;
                    127:        char *p;
                    128:        int len, sw;
1.1       markus    129:
1.4       markus    130:        len = sw = 0;
1.1       markus    131:
1.5     ! markus    132:        if (sc_fd < 0)
        !           133:                if (sc_init() < 0)
        !           134:                        return -1;
        !           135:
1.1       markus    136:        /* get key size */
1.4       markus    137:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
                    138:             sizeof(buf), buf, &sw);
                    139:        if (!sectok_swOK(sw)) {
                    140:                error("could not obtain key length: %s", sectok_get_sw(sw));
1.5     ! markus    141:                sc_close();
1.4       markus    142:                return -1;
1.1       markus    143:        }
                    144:        len = (buf[0] << 8) | buf[1];
                    145:        len /= 8;
1.4       markus    146:        debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
1.1       markus    147:
1.4       markus    148:        n = xmalloc(len);
1.1       markus    149:        /* get n */
1.4       markus    150:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
                    151:        if (!sectok_swOK(sw)) {
                    152:                error("could not obtain public key: %s", sectok_get_sw(sw));
                    153:                xfree(n);
                    154:                return -1;
1.1       markus    155:        }
1.4       markus    156:        debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
                    157:
                    158:        if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
                    159:                error("c_read_pubkey: BN_bin2bn failed");
                    160:                xfree(n);
1.5     ! markus    161:                sc_close();
1.4       markus    162:                return -1;
                    163:        }
                    164:        xfree(n);
1.1       markus    165:
                    166:        /* currently the java applet just stores 'n' */
1.4       markus    167:        if (!BN_set_word(k->rsa->e, 35)) {
                    168:                error("c_read_pubkey: BN_set_word(e, 35) failed");
                    169:                return -1;
                    170:        }
1.1       markus    171:
                    172:        p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
                    173:        debug("fingerprint %d %s", key_size(k), p);
                    174:        xfree(p);
                    175:
                    176:        return 0;
                    177: }
                    178:
                    179: /* private key operations */
                    180:
                    181: static int
1.4       markus    182: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    183: {
1.4       markus    184:        u_char *padded = NULL;
                    185:        int sw, len, olen;
1.1       markus    186:
                    187:        debug("sc_private_decrypt called");
                    188:
1.4       markus    189:        olen = len = sw = 0;
1.5     ! markus    190:        if (sc_fd < 0)
        !           191:                if (sc_init() < 0)
        !           192:                        goto err;
1.4       markus    193:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    194:                goto err;
                    195:
1.4       markus    196:        len = BN_num_bytes(rsa->n);
                    197:        padded = xmalloc(len);
1.1       markus    198:
1.4       markus    199:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
                    200:        if (!sectok_swOK(sw)) {
                    201:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
                    202:                    sectok_get_sw(sw));
1.5     ! markus    203:                sc_close();
1.1       markus    204:                goto err;
                    205:        }
1.4       markus    206:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
                    207:             len, padded, &sw);
                    208:        if (!sectok_swOK(sw)) {
                    209:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
                    210:                    sectok_get_sw(sw));
1.5     ! markus    211:                sc_close();
1.1       markus    212:                goto err;
                    213:        }
1.4       markus    214:        olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
                    215:            len);
1.1       markus    216: err:
                    217:        if (padded)
                    218:                xfree(padded);
                    219:        return olen;
                    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;
                    226:        int sw, len;
1.1       markus    227:
1.4       markus    228:        len = sw = 0;
1.5     ! markus    229:        if (sc_fd < 0)
        !           230:                if (sc_init() < 0)
        !           231:                        goto err;
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.4       markus    261:        return len;
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;
                    331:
1.5     ! markus    332:        sc_reader_num = num;
1.1       markus    333:        k = key_new(KEY_RSA);
                    334:        if (k == NULL) {
                    335:                return NULL;
                    336:        }
1.4       markus    337:        if (sc_read_pubkey(k) < 0) {
1.1       markus    338:                error("sc_read_pubkey failed");
                    339:                key_free(k);
                    340:                return NULL;
                    341:        }
                    342:        return k;
1.5     ! markus    343:        sc_close();
1.1       markus    344: }
                    345: #endif