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