Annotation of src/usr.bin/ssh/scard.c, Revision 1.14.4.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.14.4.4! miod 27: RCSID("$OpenBSD: scard.c,v 1.25 2002/03/26 18:46:59 rees Exp $");
1.1 markus 28:
1.14.4.4! miod 29: #include <openssl/evp.h>
1.1 markus 30: #include <sectok.h>
31:
32: #include "key.h"
33: #include "log.h"
34: #include "xmalloc.h"
1.14.4.4! miod 35: #include "readpass.h"
1.1 markus 36: #include "scard.h"
37:
1.14.4.4! miod 38: #if OPENSSL_VERSION_NUMBER < 0x00907000L
! 39: #define USE_ENGINE
! 40: #define RSA_get_default_method RSA_get_default_openssl_method
! 41: #else
! 42: #endif
! 43:
! 44: #ifdef USE_ENGINE
! 45: #include <openssl/engine.h>
! 46: #define sc_get_rsa sc_get_engine
! 47: #else
! 48: #define sc_get_rsa sc_get_rsa_method
! 49: #endif
! 50:
1.1 markus 51: #define CLA_SSH 0x05
52: #define INS_DECRYPT 0x10
53: #define INS_GET_KEYLENGTH 0x20
54: #define INS_GET_PUBKEY 0x30
55: #define INS_GET_RESPONSE 0xc0
56:
57: #define MAX_BUF_SIZE 256
58:
1.14.4.4! miod 59: u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
! 60:
1.1 markus 61: static int sc_fd = -1;
1.11 markus 62: static char *sc_reader_id = NULL;
1.14.4.4! miod 63: static char *sc_pin = NULL;
1.1 markus 64: static int cla = 0x00; /* class */
65:
1.14.4.4! miod 66: static void sc_mk_digest(const char *pin, u_char *digest);
! 67: static int get_AUT0(u_char *aut0);
! 68: static int try_AUT0(void);
! 69:
1.1 markus 70: /* interface to libsectok */
71:
1.14.4.3 miod 72: static int
1.5 markus 73: sc_open(void)
1.1 markus 74: {
1.4 markus 75: int sw;
1.1 markus 76:
77: if (sc_fd >= 0)
78: return sc_fd;
79:
1.11 markus 80: sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
1.1 markus 81: if (sc_fd < 0) {
1.5 markus 82: error("sectok_open failed: %s", sectok_get_sw(sw));
1.8 jakob 83: return SCARD_ERROR_FAIL;
84: }
85: if (! sectok_cardpresent(sc_fd)) {
1.11 markus 86: debug("smartcard in reader %s not present, skipping",
87: sc_reader_id);
1.10 jakob 88: sc_close();
1.8 jakob 89: return SCARD_ERROR_NOCARD;
1.1 markus 90: }
1.7 rees 91: if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
1.4 markus 92: error("sectok_reset failed: %s", sectok_get_sw(sw));
1.1 markus 93: sc_fd = -1;
1.8 jakob 94: return SCARD_ERROR_FAIL;
1.1 markus 95: }
1.7 rees 96: if ((cla = cyberflex_inq_class(sc_fd)) < 0)
97: cla = 0;
1.5 markus 98:
1.4 markus 99: debug("sc_open ok %d", sc_fd);
1.1 markus 100: return sc_fd;
101: }
102:
1.14.4.3 miod 103: static int
1.4 markus 104: sc_enable_applet(void)
1.1 markus 105: {
1.7 rees 106: static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
107: int sw = 0;
1.1 markus 108:
1.7 rees 109: /* select applet id */
110: sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
1.4 markus 111: if (!sectok_swOK(sw)) {
112: error("sectok_apdu failed: %s", sectok_get_sw(sw));
1.5 markus 113: sc_close();
114: return -1;
115: }
116: return 0;
117: }
118:
1.14.4.3 miod 119: static int
1.5 markus 120: sc_init(void)
121: {
1.8 jakob 122: int status;
123:
124: status = sc_open();
125: if (status == SCARD_ERROR_NOCARD) {
126: return SCARD_ERROR_NOCARD;
127: }
128: if (status < 0 ) {
1.5 markus 129: error("sc_open failed");
1.8 jakob 130: return status;
1.5 markus 131: }
132: if (sc_enable_applet() < 0) {
133: error("sc_enable_applet failed");
1.8 jakob 134: return SCARD_ERROR_APPLET;
1.1 markus 135: }
136: return 0;
137: }
138:
1.14.4.3 miod 139: static int
1.1 markus 140: sc_read_pubkey(Key * k)
141: {
1.4 markus 142: u_char buf[2], *n;
143: char *p;
1.14 markus 144: int len, sw, status = -1;
1.1 markus 145:
1.4 markus 146: len = sw = 0;
1.14.4.2 miod 147: n = NULL;
1.1 markus 148:
1.8 jakob 149: if (sc_fd < 0) {
1.14.4.4! miod 150: if (sc_init() < 0)
1.14 markus 151: goto err;
1.8 jakob 152: }
1.5 markus 153:
1.1 markus 154: /* get key size */
1.4 markus 155: sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
1.14.4.3 miod 156: sizeof(buf), buf, &sw);
1.4 markus 157: if (!sectok_swOK(sw)) {
158: error("could not obtain key length: %s", sectok_get_sw(sw));
1.14 markus 159: goto err;
1.1 markus 160: }
161: len = (buf[0] << 8) | buf[1];
162: len /= 8;
1.4 markus 163: debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
1.1 markus 164:
1.4 markus 165: n = xmalloc(len);
1.1 markus 166: /* get n */
1.4 markus 167: sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
1.14.4.4! miod 168:
! 169: if (sw == 0x6982) {
! 170: if (try_AUT0() < 0)
! 171: goto err;
! 172: sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
! 173: }
1.4 markus 174: if (!sectok_swOK(sw)) {
175: error("could not obtain public key: %s", sectok_get_sw(sw));
1.14 markus 176: goto err;
1.1 markus 177: }
1.14 markus 178:
1.4 markus 179: debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
180:
181: if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
182: error("c_read_pubkey: BN_bin2bn failed");
1.14 markus 183: goto err;
1.4 markus 184: }
1.1 markus 185:
186: /* currently the java applet just stores 'n' */
1.4 markus 187: if (!BN_set_word(k->rsa->e, 35)) {
188: error("c_read_pubkey: BN_set_word(e, 35) failed");
1.14 markus 189: goto err;
1.4 markus 190: }
1.1 markus 191:
1.14 markus 192: status = 0;
1.1 markus 193: p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
194: debug("fingerprint %d %s", key_size(k), p);
195: xfree(p);
196:
1.14 markus 197: err:
198: if (n != NULL)
199: xfree(n);
200: sc_close();
201: return status;
1.1 markus 202: }
203:
204: /* private key operations */
205:
206: static int
1.14.4.4! miod 207: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
! 208: int padding)
1.1 markus 209: {
1.4 markus 210: u_char *padded = NULL;
1.14 markus 211: int sw, len, olen, status = -1;
1.1 markus 212:
213: debug("sc_private_decrypt called");
214:
1.4 markus 215: olen = len = sw = 0;
1.8 jakob 216: if (sc_fd < 0) {
217: status = sc_init();
218: if (status < 0 )
1.5 markus 219: goto err;
1.8 jakob 220: }
1.4 markus 221: if (padding != RSA_PKCS1_PADDING)
1.1 markus 222: goto err;
223:
1.4 markus 224: len = BN_num_bytes(rsa->n);
225: padded = xmalloc(len);
1.1 markus 226:
1.14.4.4! miod 227: sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
! 228:
! 229: if (sw == 0x6982) {
! 230: if (try_AUT0() < 0)
! 231: goto err;
! 232: sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
1.1 markus 233: }
1.4 markus 234: if (!sectok_swOK(sw)) {
1.14.4.4! miod 235: error("sc_private_decrypt: INS_DECRYPT failed: %s",
1.4 markus 236: sectok_get_sw(sw));
1.1 markus 237: goto err;
238: }
1.4 markus 239: olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
240: len);
1.1 markus 241: err:
242: if (padded)
243: xfree(padded);
1.14 markus 244: sc_close();
1.8 jakob 245: return (olen >= 0 ? olen : status);
1.1 markus 246: }
247:
248: static int
1.14.4.4! miod 249: sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
! 250: int padding)
1.1 markus 251: {
1.4 markus 252: u_char *padded = NULL;
1.14 markus 253: int sw, len, status = -1;
1.1 markus 254:
1.4 markus 255: len = sw = 0;
1.8 jakob 256: if (sc_fd < 0) {
257: status = sc_init();
258: if (status < 0 )
1.5 markus 259: goto err;
1.8 jakob 260: }
1.4 markus 261: if (padding != RSA_PKCS1_PADDING)
1.1 markus 262: goto err;
263:
1.3 markus 264: debug("sc_private_encrypt called");
1.4 markus 265: len = BN_num_bytes(rsa->n);
266: padded = xmalloc(len);
267:
1.14.4.4! miod 268: if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) {
1.1 markus 269: error("RSA_padding_add_PKCS1_type_1 failed");
270: goto err;
271: }
1.14.4.4! miod 272: sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
! 273: if (sw == 0x6982) {
! 274: if (try_AUT0() < 0)
! 275: goto err;
! 276: sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
1.4 markus 277: }
278: if (!sectok_swOK(sw)) {
1.14.4.4! miod 279: error("sc_private_encrypt: INS_DECRYPT failed: %s",
1.4 markus 280: sectok_get_sw(sw));
281: goto err;
1.1 markus 282: }
283: err:
284: if (padded)
285: xfree(padded);
1.14 markus 286: sc_close();
1.8 jakob 287: return (len >= 0 ? len : status);
1.1 markus 288: }
289:
1.12 markus 290: /* called on free */
291:
292: static int (*orig_finish)(RSA *rsa) = NULL;
293:
294: static int
295: sc_finish(RSA *rsa)
296: {
297: if (orig_finish)
298: orig_finish(rsa);
299: sc_close();
300: return 1;
301: }
302:
1.1 markus 303: /* engine for overloading private key operations */
304:
1.14.4.4! miod 305: static RSA_METHOD *
! 306: sc_get_rsa_method(void)
1.1 markus 307: {
1.14.4.4! miod 308: static RSA_METHOD smart_rsa;
! 309: const RSA_METHOD *def = RSA_get_default_method();
1.1 markus 310:
1.14.4.4! miod 311: /* use the OpenSSL version */
! 312: memcpy(&smart_rsa, def, sizeof(smart_rsa));
1.1 markus 313:
1.14.4.4! miod 314: smart_rsa.name = "sectok";
1.1 markus 315:
316: /* overload */
317: smart_rsa.rsa_priv_enc = sc_private_encrypt;
318: smart_rsa.rsa_priv_dec = sc_private_decrypt;
319:
1.12 markus 320: /* save original */
321: orig_finish = def->finish;
322: smart_rsa.finish = sc_finish;
323:
1.14.4.4! miod 324: return &smart_rsa;
! 325: }
! 326:
! 327: #ifdef USE_ENGINE
! 328: static ENGINE *
! 329: sc_get_engine(void)
! 330: {
! 331: static ENGINE *smart_engine = NULL;
1.1 markus 332:
1.14.4.3 miod 333: if ((smart_engine = ENGINE_new()) == NULL)
334: fatal("ENGINE_new failed");
1.1 markus 335:
1.4 markus 336: ENGINE_set_id(smart_engine, "sectok");
337: ENGINE_set_name(smart_engine, "libsectok");
1.14.4.4! miod 338:
! 339: ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
1.1 markus 340: ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
341: ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
342: ENGINE_set_RAND(smart_engine, RAND_SSLeay());
343: ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
344:
345: return smart_engine;
346: }
1.14.4.4! miod 347: #endif
1.1 markus 348:
1.5 markus 349: void
350: sc_close(void)
351: {
352: if (sc_fd >= 0) {
353: sectok_close(sc_fd);
354: sc_fd = -1;
355: }
356: }
357:
1.14.4.4! miod 358: Key **
! 359: sc_get_keys(const char *id, const char *pin)
1.1 markus 360: {
1.14.4.4! miod 361: Key *k, *n, **keys;
! 362: int status, nkeys = 2;
1.1 markus 363:
1.11 markus 364: if (sc_reader_id != NULL)
365: xfree(sc_reader_id);
366: sc_reader_id = xstrdup(id);
367:
1.14.4.4! miod 368: if (sc_pin != NULL)
! 369: xfree(sc_pin);
! 370: sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
! 371:
1.1 markus 372: k = key_new(KEY_RSA);
373: if (k == NULL) {
374: return NULL;
375: }
1.9 jakob 376: status = sc_read_pubkey(k);
377: if (status == SCARD_ERROR_NOCARD) {
378: key_free(k);
379: return NULL;
380: }
381: if (status < 0 ) {
1.1 markus 382: error("sc_read_pubkey failed");
383: key_free(k);
384: return NULL;
385: }
1.14.4.4! miod 386: keys = xmalloc((nkeys+1) * sizeof(Key *));
! 387:
! 388: n = key_new(KEY_RSA1);
! 389: BN_copy(n->rsa->n, k->rsa->n);
! 390: BN_copy(n->rsa->e, k->rsa->e);
! 391: RSA_set_method(n->rsa, sc_get_rsa());
! 392: n->flags |= KEY_FLAG_EXT;
! 393: keys[0] = n;
! 394:
! 395: n = key_new(KEY_RSA);
! 396: BN_copy(n->rsa->n, k->rsa->n);
! 397: BN_copy(n->rsa->e, k->rsa->e);
! 398: RSA_set_method(n->rsa, sc_get_rsa());
! 399: n->flags |= KEY_FLAG_EXT;
! 400: keys[1] = n;
! 401:
! 402: keys[2] = NULL;
! 403:
! 404: key_free(k);
! 405: return keys;
! 406: }
! 407:
! 408: #define NUM_RSA_KEY_ELEMENTS 5+1
! 409: #define COPY_RSA_KEY(x, i) \
! 410: do { \
! 411: len = BN_num_bytes(prv->rsa->x); \
! 412: elements[i] = xmalloc(len); \
! 413: debug("#bytes %d", len); \
! 414: if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \
! 415: goto done; \
! 416: } while (0)
! 417:
! 418: static void
! 419: sc_mk_digest(const char *pin, u_char *digest)
! 420: {
! 421: const EVP_MD *evp_md = EVP_sha1();
! 422: EVP_MD_CTX md;
! 423:
! 424: EVP_DigestInit(&md, evp_md);
! 425: EVP_DigestUpdate(&md, pin, strlen(pin));
! 426: EVP_DigestFinal(&md, digest, NULL);
! 427: }
! 428:
! 429: static int
! 430: get_AUT0(u_char *aut0)
! 431: {
! 432: char *pass;
! 433:
! 434: pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
! 435: if (pass == NULL)
! 436: return -1;
! 437: if (!strcmp(pass, "-")) {
! 438: memcpy(aut0, DEFAUT0, sizeof DEFAUT0);
! 439: return 0;
! 440: }
! 441: sc_mk_digest(pass, aut0);
! 442: memset(pass, 0, strlen(pass));
! 443: xfree(pass);
! 444: return 0;
! 445: }
! 446:
! 447: static int
! 448: try_AUT0(void)
! 449: {
! 450: u_char aut0[EVP_MAX_MD_SIZE];
! 451:
! 452: /* permission denied; try PIN if provided */
! 453: if (sc_pin && strlen(sc_pin) > 0) {
! 454: sc_mk_digest(sc_pin, aut0);
! 455: if (cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
! 456: error("smartcard passphrase incorrect");
! 457: return (-1);
! 458: }
! 459: } else {
! 460: /* try default AUT0 key */
! 461: if (cyberflex_verify_AUT0(sc_fd, cla, DEFAUT0, 8) < 0) {
! 462: /* default AUT0 key failed; prompt for passphrase */
! 463: if (get_AUT0(aut0) < 0 ||
! 464: cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
! 465: error("smartcard passphrase incorrect");
! 466: return (-1);
! 467: }
! 468: }
! 469: }
! 470: return (0);
! 471: }
! 472:
! 473: int
! 474: sc_put_key(Key *prv, const char *id)
! 475: {
! 476: u_char *elements[NUM_RSA_KEY_ELEMENTS];
! 477: u_char key_fid[2];
! 478: u_char AUT0[EVP_MAX_MD_SIZE];
! 479: int len, status = -1, i, fd = -1, ret;
! 480: int sw = 0, cla = 0x00;
! 481:
! 482: for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
! 483: elements[i] = NULL;
! 484:
! 485: COPY_RSA_KEY(q, 0);
! 486: COPY_RSA_KEY(p, 1);
! 487: COPY_RSA_KEY(iqmp, 2);
! 488: COPY_RSA_KEY(dmq1, 3);
! 489: COPY_RSA_KEY(dmp1, 4);
! 490: COPY_RSA_KEY(n, 5);
! 491: len = BN_num_bytes(prv->rsa->n);
! 492: fd = sectok_friendly_open(id, STONOWAIT, &sw);
! 493: if (fd < 0) {
! 494: error("sectok_open failed: %s", sectok_get_sw(sw));
! 495: goto done;
! 496: }
! 497: if (! sectok_cardpresent(fd)) {
! 498: error("smartcard in reader %s not present", id);
! 499: goto done;
! 500: }
! 501: ret = sectok_reset(fd, 0, NULL, &sw);
! 502: if (ret <= 0) {
! 503: error("sectok_reset failed: %s", sectok_get_sw(sw));
! 504: goto done;
! 505: }
! 506: if ((cla = cyberflex_inq_class(fd)) < 0) {
! 507: error("cyberflex_inq_class failed");
! 508: goto done;
! 509: }
! 510: memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0));
! 511: if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
! 512: if (get_AUT0(AUT0) < 0 ||
! 513: cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
! 514: memset(AUT0, 0, sizeof(DEFAUT0));
! 515: error("smartcard passphrase incorrect");
! 516: goto done;
! 517: }
! 518: }
! 519: memset(AUT0, 0, sizeof(DEFAUT0));
! 520: key_fid[0] = 0x00;
! 521: key_fid[1] = 0x12;
! 522: if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements,
! 523: &sw) < 0) {
! 524: error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw));
! 525: goto done;
! 526: }
! 527: if (!sectok_swOK(sw))
! 528: goto done;
! 529: log("cyberflex_load_rsa_priv done");
! 530: key_fid[0] = 0x73;
! 531: key_fid[1] = 0x68;
! 532: if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5],
! 533: &sw) < 0) {
! 534: error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw));
! 535: goto done;
! 536: }
! 537: if (!sectok_swOK(sw))
! 538: goto done;
! 539: log("cyberflex_load_rsa_pub done");
! 540: status = 0;
! 541:
! 542: done:
! 543: memset(elements[0], '\0', BN_num_bytes(prv->rsa->q));
! 544: memset(elements[1], '\0', BN_num_bytes(prv->rsa->p));
! 545: memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp));
! 546: memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1));
! 547: memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1));
! 548: memset(elements[5], '\0', BN_num_bytes(prv->rsa->n));
! 549:
! 550: for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
! 551: if (elements[i])
! 552: xfree(elements[i]);
! 553: if (fd != -1)
! 554: sectok_close(fd);
! 555: return (status);
1.1 markus 556: }
1.13 jakob 557: #endif /* SMARTCARD */