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

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.4     ! markus     27: RCSID("$OpenBSD: scard.c,v 1.3 2001/06/26 20:14:10 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;
                     46: static int sc_reader_num = 0;
                     47: static int cla = 0x00; /* class */
                     48:
                     49: /* interface to libsectok */
                     50:
                     51: static int
                     52: sc_open(int num)
                     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:        sc_reader_num = num;
                     60:
1.4     ! markus     61:        sc_fd = sectok_open(sc_reader_num, 0, NULL);
1.1       markus     62:        if (sc_fd < 0) {
1.4     ! markus     63:                error("sectok_open failed %d", sc_fd);
1.1       markus     64:                return sc_fd;
                     65:        }
1.4     ! markus     66:        if (sectok_reset(sc_fd, 0, atr, &sw) <= 0) {
        !            67:                error("sectok_reset failed: %s", sectok_get_sw(sw));
1.1       markus     68:                sc_fd = -1;
                     69:                return sc_fd;
                     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.1       markus     88:                return -1;
                     89:        }
1.4     ! markus     90:        if (sectok_selectfile(sc_fd, cla, contID, &sw) < 0) {
        !            91:                error("sectok_selectfile failed: %s", sectok_get_sw(sw));
        !            92:                return -1;
        !            93:        }
        !            94:        /* send appled id */
        !            95:        for (i = 0; i < sizeof(aid); i++)
        !            96:                aid[i] = 0x77;
        !            97:        aid_len = 5;
        !            98:        sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, aid_len, aid, 0, NULL, &sw);
        !            99:        if (!sectok_swOK(sw)) {
        !           100:                error("sectok_apdu failed: %s", sectok_get_sw(sw));
1.1       markus    101:                return -1;
                    102:        }
                    103:        return 0;
                    104: }
                    105:
                    106: static int
                    107: sc_read_pubkey(Key * k)
                    108: {
1.4     ! markus    109:        u_char buf[2], *n;
        !           110:        char *p;
        !           111:        int len, sw;
1.1       markus    112:
1.4     ! markus    113:        len = sw = 0;
1.1       markus    114:
                    115:        /* get key size */
1.4     ! markus    116:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
        !           117:             sizeof(buf), buf, &sw);
        !           118:        if (!sectok_swOK(sw)) {
        !           119:                error("could not obtain key length: %s", sectok_get_sw(sw));
        !           120:                return -1;
1.1       markus    121:        }
                    122:        len = (buf[0] << 8) | buf[1];
                    123:        len /= 8;
1.4     ! markus    124:        debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
1.1       markus    125:
1.4     ! markus    126:        n = xmalloc(len);
1.1       markus    127:        /* get n */
1.4     ! markus    128:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
        !           129:        if (!sectok_swOK(sw)) {
        !           130:                error("could not obtain public key: %s", sectok_get_sw(sw));
        !           131:                xfree(n);
        !           132:                return -1;
1.1       markus    133:        }
1.4     ! markus    134:        debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
        !           135:
        !           136:        if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
        !           137:                error("c_read_pubkey: BN_bin2bn failed");
        !           138:                xfree(n);
        !           139:                return -1;
        !           140:        }
        !           141:        xfree(n);
1.1       markus    142:
                    143:        /* currently the java applet just stores 'n' */
1.4     ! markus    144:        if (!BN_set_word(k->rsa->e, 35)) {
        !           145:                error("c_read_pubkey: BN_set_word(e, 35) failed");
        !           146:                return -1;
        !           147:        }
1.1       markus    148:
                    149:        p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
                    150:        debug("fingerprint %d %s", key_size(k), p);
                    151:        xfree(p);
                    152:
                    153:        return 0;
                    154: }
                    155:
                    156: /* private key operations */
                    157:
                    158: static int
1.4     ! markus    159: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    160: {
1.4     ! markus    161:        u_char *padded = NULL;
        !           162:        int sw, len, olen;
1.1       markus    163:
                    164:        debug("sc_private_decrypt called");
                    165:
1.4     ! markus    166:        olen = len = sw = 0;
        !           167:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    168:                goto err;
                    169:
1.4     ! markus    170:        len = BN_num_bytes(rsa->n);
        !           171:        padded = xmalloc(len);
1.1       markus    172:
1.4     ! markus    173:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
        !           174:        if (!sectok_swOK(sw)) {
        !           175:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
        !           176:                    sectok_get_sw(sw));
1.1       markus    177:                goto err;
                    178:        }
1.4     ! markus    179:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
        !           180:             len, padded, &sw);
        !           181:        if (!sectok_swOK(sw)) {
        !           182:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
        !           183:                    sectok_get_sw(sw));
1.1       markus    184:                goto err;
                    185:        }
1.4     ! markus    186:        olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
        !           187:            len);
1.1       markus    188: err:
                    189:        if (padded)
                    190:                xfree(padded);
                    191:        return olen;
                    192: }
                    193:
                    194: static int
1.4     ! markus    195: sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1       markus    196: {
1.4     ! markus    197:        u_char *padded = NULL;
        !           198:        int sw, len;
1.1       markus    199:
1.4     ! markus    200:        len = sw = 0;
        !           201:        if (padding != RSA_PKCS1_PADDING)
1.1       markus    202:                goto err;
                    203:
1.3       markus    204:        debug("sc_private_encrypt called");
1.4     ! markus    205:        len = BN_num_bytes(rsa->n);
        !           206:        padded = xmalloc(len);
        !           207:
        !           208:        if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
1.1       markus    209:                error("RSA_padding_add_PKCS1_type_1 failed");
                    210:                goto err;
                    211:        }
1.4     ! markus    212:        sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
        !           213:        if (!sectok_swOK(sw)) {
        !           214:                error("sc_private_decrypt: INS_DECRYPT failed: %s",
        !           215:                    sectok_get_sw(sw));
        !           216:                goto err;
        !           217:        }
        !           218:        sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
        !           219:             len, to, &sw);
        !           220:        if (!sectok_swOK(sw)) {
        !           221:                error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
        !           222:                    sectok_get_sw(sw));
        !           223:                goto err;
1.1       markus    224:        }
                    225: err:
                    226:        if (padded)
                    227:                xfree(padded);
1.4     ! markus    228:        return len;
1.1       markus    229: }
                    230:
                    231: /* engine for overloading private key operations */
                    232:
                    233: static ENGINE *smart_engine = NULL;
                    234: static RSA_METHOD smart_rsa =
                    235: {
1.4     ! markus    236:        "sectok",
        !           237:        NULL,
        !           238:        NULL,
        !           239:        NULL,
        !           240:        NULL,
        !           241:        NULL,
        !           242:        NULL,
        !           243:        NULL,
        !           244:        NULL,
        !           245:        0,
        !           246:        NULL,
1.1       markus    247: };
                    248:
                    249: ENGINE *
1.2       itojun    250: sc_get_engine(void)
1.1       markus    251: {
                    252:        RSA_METHOD *def;
                    253:
                    254:        def = RSA_get_default_openssl_method();
                    255:
                    256:        /* overload */
                    257:        smart_rsa.rsa_priv_enc  = sc_private_encrypt;
                    258:        smart_rsa.rsa_priv_dec  = sc_private_decrypt;
                    259:
                    260:        /* just use the OpenSSL version */
1.4     ! markus    261:        smart_rsa.rsa_pub_enc   = def->rsa_pub_enc;
        !           262:        smart_rsa.rsa_pub_dec   = def->rsa_pub_dec;
1.1       markus    263:        smart_rsa.rsa_mod_exp   = def->rsa_mod_exp;
                    264:        smart_rsa.bn_mod_exp    = def->bn_mod_exp;
                    265:        smart_rsa.init          = def->init;
                    266:        smart_rsa.finish        = def->finish;
                    267:        smart_rsa.flags         = def->flags;
                    268:        smart_rsa.app_data      = def->app_data;
                    269:        smart_rsa.rsa_sign      = def->rsa_sign;
                    270:        smart_rsa.rsa_verify    = def->rsa_verify;
                    271:
                    272:        smart_engine = ENGINE_new();
                    273:
1.4     ! markus    274:        ENGINE_set_id(smart_engine, "sectok");
        !           275:        ENGINE_set_name(smart_engine, "libsectok");
1.1       markus    276:        ENGINE_set_RSA(smart_engine, &smart_rsa);
                    277:        ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
                    278:        ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
                    279:        ENGINE_set_RAND(smart_engine, RAND_SSLeay());
                    280:        ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
                    281:
                    282:        return smart_engine;
                    283: }
                    284:
                    285: Key *
                    286: sc_get_key(int sc_reader_num)
                    287: {
                    288:        Key *k;
                    289:
1.4     ! markus    290:        if (sc_open(sc_reader_num) < 0) {
1.1       markus    291:                error("sc_open failed");
                    292:                return NULL;
                    293:        }
1.4     ! markus    294:        if (sc_enable_applet() < 0) {
1.1       markus    295:                error("sc_enable_applet failed");
                    296:                return NULL;
                    297:        }
                    298:        k = key_new(KEY_RSA);
                    299:        if (k == NULL) {
                    300:                return NULL;
                    301:        }
1.4     ! markus    302:        if (sc_read_pubkey(k) < 0) {
1.1       markus    303:                error("sc_read_pubkey failed");
                    304:                key_free(k);
                    305:                return NULL;
                    306:        }
                    307:        return k;
                    308: }
                    309: #endif