Annotation of src/usr.bin/ssh/scard.c, Revision 1.1
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"
! 27: RCSID("$OpenBSD: ssh-agent.c,v 1.56 2001/06/25 08:25:40 markus Exp $");
! 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: int n;
! 55: u_char atr[256];
! 56:
! 57: if (sc_fd >= 0)
! 58: return sc_fd;
! 59: sc_reader_num = num;
! 60:
! 61: sc_fd = scopen(sc_reader_num, 0, NULL);
! 62: if (sc_fd < 0) {
! 63: error("scopen failed %d", sc_fd);
! 64: return sc_fd;
! 65: }
! 66: n = screset(sc_fd, atr, NULL);
! 67: if (n <= 0) {
! 68: error("screset failed.");
! 69: sc_fd = -1;
! 70: return sc_fd;
! 71: }
! 72: debug("open ok %d", sc_fd);
! 73: return sc_fd;
! 74: }
! 75:
! 76: static int
! 77: sc_reset(void)
! 78: {
! 79: scclose(sc_fd);
! 80: sc_fd = -1;
! 81: return sc_open(sc_reader_num);
! 82: }
! 83:
! 84: static int
! 85: selectfile(int fd, int f0, int f1, int verbose)
! 86: {
! 87: int n, r1, r2, code;
! 88: u_char buf[2], obuf[256];
! 89:
! 90: buf[0] = f0;
! 91: buf[1] = f1;
! 92: n = scrw(sc_fd, cla, 0xa4, 0, 0, 2, buf, sizeof obuf, obuf, &r1, &r2);
! 93: if (n < 0) {
! 94: error("selectfile: scwrite failed");
! 95: return -2;
! 96: }
! 97: if (r1 == 0x90 || r1 == 0x61)
! 98: code = 0;
! 99: else if (r1 == 0x6a && r2 == 0x82)
! 100: /* file not found */
! 101: code = -1;
! 102: else
! 103: code = -2;
! 104: if (verbose && n > 0)
! 105: dump_reply(obuf, n, 0, 0);
! 106: if (verbose || code == -2) {
! 107: error("%x.%x: %s", f0, f1, get_r1r2s(r1, r2));
! 108: }
! 109: return code;
! 110: }
! 111:
! 112: static int
! 113: sc_enable_applet(void)
! 114: {
! 115: u_char data[MAX_BUF_SIZE];
! 116: u_char progID[2], contID[2], aid[MAX_BUF_SIZE];
! 117: int i, len, rv, r1, r2, aid_len;
! 118:
! 119: len = rv = r1 = r2 = 0;
! 120: progID[0] = 0x77;
! 121: progID[1] = 0x77;
! 122: contID[0] = 0x77;
! 123: contID[1] = 0x78;
! 124: aid_len = 5;
! 125:
! 126: for (i = 0; i < 16; i++)
! 127: aid[i] = 0x77;
! 128:
! 129: rv = selectfile(sc_fd, contID[0], contID[1], 0);
! 130: if (rv < 0) {
! 131: error("selectfile failed");
! 132: return -1;
! 133: }
! 134: for (i = 0; i < aid_len; i++)
! 135: data[i] = (u_char) aid[i];
! 136: rv = scwrite(sc_fd, cla, 0xa4, 0x04, 0, aid_len, data, &r1, &r2);
! 137: if (r1 != 0x90 && r1 != 0x61) {
! 138: /* error */
! 139: error("selecting the cardlet: ");
! 140: for (i = 0; i < aid_len; i++) {
! 141: error("%02x", (u_char) aid[i]);
! 142: }
! 143: print_r1r2(r1, r2);
! 144: return -1;
! 145: }
! 146: return 0;
! 147: }
! 148:
! 149: static int
! 150: sc_read_pubkey(Key * k)
! 151: {
! 152: u_char buf[256];
! 153: char *p;
! 154: int len, rv, r1, r2;
! 155:
! 156: len = rv = r1 = r2 = 0;
! 157:
! 158: /* get key size */
! 159: rv = scread(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 2, buf, &r1, &r2);
! 160: if (rv < 0) {
! 161: error("could not obtain key length.");
! 162: return rv;
! 163: }
! 164: len = (buf[0] << 8) | buf[1];
! 165: error("len %d r1 %d r2 %d", len, r1, r2);
! 166: len /= 8;
! 167:
! 168: /* get n */
! 169: rv = scread(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, len, buf, &r1, &r2);
! 170: if (rv < 0) {
! 171: error("could not obtain public key");
! 172: return rv;
! 173: }
! 174: debug("len %d r1 %d r2 %d", len, r1, r2);
! 175: BN_bin2bn(buf, len, k->rsa->n);
! 176:
! 177: /* currently the java applet just stores 'n' */
! 178: BN_set_word(k->rsa->e, 35); /* XXX */
! 179:
! 180: p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
! 181: debug("fingerprint %d %s", key_size(k), p);
! 182: xfree(p);
! 183:
! 184: return 0;
! 185: }
! 186:
! 187: /* private key operations */
! 188:
! 189: static int
! 190: sc_private_decrypt(int flen, unsigned char *from,
! 191: unsigned char *to, RSA *rsa, int padding)
! 192: {
! 193: int rv, num, r1, r2, olen;
! 194: u_char *padded = NULL;
! 195:
! 196: debug("sc_private_decrypt called");
! 197:
! 198: olen = num = r1 = r2 = 0;
! 199: if (padding != RSA_PKCS1_PADDING)
! 200: goto err;
! 201:
! 202: num = BN_num_bytes(rsa->n);
! 203: padded = xmalloc(num);
! 204:
! 205: rv = scwrite(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, num, from, &r1, &r2);
! 206: if (rv < 0) {
! 207: error("scwrite() for decrypt failed.");
! 208: goto err;
! 209: }
! 210: if (r1 != 0x90 && r1 != 0x61) {
! 211: error("INS_DECRYPT: r1 %x r2 %x", r1, r2);
! 212: goto err;
! 213: }
! 214: rv = scread(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, num, padded, &r1, &r2);
! 215: if (rv < 0) {
! 216: error("scread() for decrypt failed");
! 217: goto err;
! 218: }
! 219: if (r1 != 0x90 && r1 != 0x61) {
! 220: error("INS_GET_RESPONSE: r1 %x r2 %x", r1, r2);
! 221: goto err;
! 222: }
! 223: debug("r1 %x r2 %x", r1, r2);
! 224: olen = RSA_padding_check_PKCS1_type_2(to, num, padded + 1, num - 1, num);
! 225: err:
! 226: if (padded)
! 227: xfree(padded);
! 228: return olen;
! 229: }
! 230:
! 231:
! 232: static int
! 233: sc_private_encrypt(int flen, unsigned char *from,
! 234: unsigned char *to, RSA *rsa, int padding)
! 235: {
! 236: int rv, i, num, r1, r2;
! 237: u_char *padded = NULL;
! 238:
! 239: num = r1 = r2 = 0;
! 240: if (padding != RSA_PKCS1_PADDING)
! 241: goto err;
! 242:
! 243: error("sc_private_encrypt called");
! 244: num = BN_num_bytes(rsa->n);
! 245: padded = xmalloc(num);
! 246: i = RSA_padding_add_PKCS1_type_1(padded, num, from, flen);
! 247: if (i <= 0) {
! 248: error("RSA_padding_add_PKCS1_type_1 failed");
! 249: goto err;
! 250: }
! 251: rv = scwrite(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, num, padded, &r1, &r2);
! 252: if (rv < 0) {
! 253: error("scwrite() for rsa failed");
! 254: sc_reset();
! 255: goto err;
! 256: }
! 257: if (r1 != 0x90 && r1 != 0x61) {
! 258: error("INS_DECRYPT: r1 %x r2 %x", r1, r2);
! 259: goto err;
! 260: }
! 261: rv = scread(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, num, to, &r1, &r2);
! 262: if (rv < 0) {
! 263: error("scread() for rsa failed");
! 264: sc_reset();
! 265: goto err;
! 266: }
! 267: if (r1 != 0x90 && r1 != 0x61) {
! 268: error("INS_GET_RESPONSE: r1 %x r2 %x", r1, r2);
! 269: goto err;
! 270: }
! 271: err:
! 272: if (padded)
! 273: xfree(padded);
! 274: return num;
! 275: }
! 276:
! 277: /* engine for overloading private key operations */
! 278:
! 279: static ENGINE *smart_engine = NULL;
! 280: static RSA_METHOD smart_rsa =
! 281: {
! 282: "smartcard",
! 283: NULL,
! 284: NULL,
! 285: NULL,
! 286: NULL,
! 287: NULL,
! 288: NULL,
! 289: NULL,
! 290: NULL,
! 291: 0,
! 292: NULL,
! 293: };
! 294:
! 295: ENGINE *
! 296: sc_get_engine()
! 297: {
! 298: RSA_METHOD *def;
! 299:
! 300: def = RSA_get_default_openssl_method();
! 301:
! 302: /* overload */
! 303: smart_rsa.rsa_priv_enc = sc_private_encrypt;
! 304: smart_rsa.rsa_priv_dec = sc_private_decrypt;
! 305:
! 306: /* just use the OpenSSL version */
! 307: smart_rsa.rsa_pub_enc = def->rsa_pub_enc;
! 308: smart_rsa.rsa_pub_dec = def->rsa_pub_dec;
! 309: smart_rsa.rsa_mod_exp = def->rsa_mod_exp;
! 310: smart_rsa.bn_mod_exp = def->bn_mod_exp;
! 311: smart_rsa.init = def->init;
! 312: smart_rsa.finish = def->finish;
! 313: smart_rsa.flags = def->flags;
! 314: smart_rsa.app_data = def->app_data;
! 315: smart_rsa.rsa_sign = def->rsa_sign;
! 316: smart_rsa.rsa_verify = def->rsa_verify;
! 317:
! 318: smart_engine = ENGINE_new();
! 319:
! 320: ENGINE_set_id(smart_engine, "xxx");
! 321: ENGINE_set_name(smart_engine, "xxx");
! 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:
! 331: Key *
! 332: sc_get_key(int sc_reader_num)
! 333: {
! 334: Key *k;
! 335: int rv;
! 336:
! 337: rv = sc_open (sc_reader_num);
! 338: if (rv < 0) {
! 339: error("sc_open failed");
! 340: return NULL;
! 341: }
! 342: rv = sc_enable_applet();
! 343: if (rv < 0) {
! 344: error("sc_enable_applet failed");
! 345: return NULL;
! 346: }
! 347: k = key_new(KEY_RSA);
! 348: if (k == NULL) {
! 349: return NULL;
! 350: }
! 351: rv = sc_read_pubkey (k);
! 352: if (rv < 0) {
! 353: error("sc_read_pubkey failed");
! 354: key_free(k);
! 355: return NULL;
! 356: }
! 357: return k;
! 358: }
! 359: #endif