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

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