Annotation of src/usr.bin/ssh/scard.c, Revision 1.14.4.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"
1.14.4.1! jason 27: RCSID("$OpenBSD: scard.c,v 1.14 2001/09/17 20:22:14 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.14 markus 123: int len, sw, status = -1;
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 )
1.14 markus 130: goto err;
1.8 jakob 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.14 markus 138: goto err;
1.1 markus 139: }
140: len = (buf[0] << 8) | buf[1];
141: len /= 8;
1.4 markus 142: debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
1.1 markus 143:
1.4 markus 144: n = xmalloc(len);
1.1 markus 145: /* get n */
1.4 markus 146: sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
147: if (!sectok_swOK(sw)) {
148: error("could not obtain public key: %s", sectok_get_sw(sw));
1.14 markus 149: goto err;
1.1 markus 150: }
1.14 markus 151:
1.4 markus 152: debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
153:
154: if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
155: error("c_read_pubkey: BN_bin2bn failed");
1.14 markus 156: goto err;
1.4 markus 157: }
1.1 markus 158:
159: /* currently the java applet just stores 'n' */
1.4 markus 160: if (!BN_set_word(k->rsa->e, 35)) {
161: error("c_read_pubkey: BN_set_word(e, 35) failed");
1.14 markus 162: goto err;
1.4 markus 163: }
1.1 markus 164:
1.14 markus 165: status = 0;
1.1 markus 166: p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
167: debug("fingerprint %d %s", key_size(k), p);
168: xfree(p);
169:
1.14 markus 170: err:
171: if (n != NULL)
172: xfree(n);
173: sc_close();
174: return status;
1.1 markus 175: }
176:
177: /* private key operations */
178:
179: static int
1.4 markus 180: sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
1.1 markus 181: {
1.4 markus 182: u_char *padded = NULL;
1.14 markus 183: int sw, len, olen, status = -1;
1.1 markus 184:
185: debug("sc_private_decrypt called");
186:
1.4 markus 187: olen = len = sw = 0;
1.8 jakob 188: if (sc_fd < 0) {
189: status = sc_init();
190: if (status < 0 )
1.5 markus 191: goto err;
1.8 jakob 192: }
1.4 markus 193: if (padding != RSA_PKCS1_PADDING)
1.1 markus 194: goto err;
195:
1.4 markus 196: len = BN_num_bytes(rsa->n);
197: padded = xmalloc(len);
1.1 markus 198:
1.4 markus 199: sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
200: if (!sectok_swOK(sw)) {
201: error("sc_private_decrypt: INS_DECRYPT failed: %s",
202: sectok_get_sw(sw));
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.1 markus 210: goto err;
211: }
1.4 markus 212: olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
213: len);
1.1 markus 214: err:
215: if (padded)
216: xfree(padded);
1.14 markus 217: sc_close();
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.14 markus 225: int sw, len, status = -1;
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));
248: goto err;
249: }
250: sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
251: len, to, &sw);
252: if (!sectok_swOK(sw)) {
253: error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
254: sectok_get_sw(sw));
255: goto err;
1.1 markus 256: }
257: err:
258: if (padded)
259: xfree(padded);
1.14 markus 260: sc_close();
1.8 jakob 261: return (len >= 0 ? len : status);
1.1 markus 262: }
263:
1.12 markus 264: /* called on free */
265:
266: static int (*orig_finish)(RSA *rsa) = NULL;
267:
268: static int
269: sc_finish(RSA *rsa)
270: {
271: if (orig_finish)
272: orig_finish(rsa);
273: sc_close();
274: return 1;
275: }
276:
277:
1.1 markus 278: /* engine for overloading private key operations */
279:
280: static ENGINE *smart_engine = NULL;
281: static RSA_METHOD smart_rsa =
282: {
1.4 markus 283: "sectok",
284: NULL,
285: NULL,
286: NULL,
287: NULL,
288: NULL,
289: NULL,
290: NULL,
291: NULL,
292: 0,
293: NULL,
1.1 markus 294: };
295:
296: ENGINE *
1.2 itojun 297: sc_get_engine(void)
1.1 markus 298: {
299: RSA_METHOD *def;
300:
301: def = RSA_get_default_openssl_method();
302:
303: /* overload */
304: smart_rsa.rsa_priv_enc = sc_private_encrypt;
305: smart_rsa.rsa_priv_dec = sc_private_decrypt;
306:
1.12 markus 307: /* save original */
308: orig_finish = def->finish;
309: smart_rsa.finish = sc_finish;
310:
1.1 markus 311: /* just use the OpenSSL version */
1.4 markus 312: smart_rsa.rsa_pub_enc = def->rsa_pub_enc;
313: smart_rsa.rsa_pub_dec = def->rsa_pub_dec;
1.1 markus 314: smart_rsa.rsa_mod_exp = def->rsa_mod_exp;
315: smart_rsa.bn_mod_exp = def->bn_mod_exp;
316: smart_rsa.init = def->init;
317: smart_rsa.flags = def->flags;
318: smart_rsa.app_data = def->app_data;
319: smart_rsa.rsa_sign = def->rsa_sign;
320: smart_rsa.rsa_verify = def->rsa_verify;
321:
322: smart_engine = ENGINE_new();
323:
1.4 markus 324: ENGINE_set_id(smart_engine, "sectok");
325: ENGINE_set_name(smart_engine, "libsectok");
1.1 markus 326: ENGINE_set_RSA(smart_engine, &smart_rsa);
327: ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
328: ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
329: ENGINE_set_RAND(smart_engine, RAND_SSLeay());
330: ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
331:
332: return smart_engine;
333: }
334:
1.5 markus 335: void
336: sc_close(void)
337: {
338: if (sc_fd >= 0) {
339: sectok_close(sc_fd);
340: sc_fd = -1;
341: }
342: }
343:
1.1 markus 344: Key *
1.11 markus 345: sc_get_key(const char *id)
1.1 markus 346: {
347: Key *k;
1.9 jakob 348: int status;
1.1 markus 349:
1.11 markus 350: if (sc_reader_id != NULL)
351: xfree(sc_reader_id);
352: sc_reader_id = xstrdup(id);
353:
1.1 markus 354: k = key_new(KEY_RSA);
355: if (k == NULL) {
356: return NULL;
357: }
1.9 jakob 358: status = sc_read_pubkey(k);
359: if (status == SCARD_ERROR_NOCARD) {
360: key_free(k);
361: return NULL;
362: }
363: if (status < 0 ) {
1.1 markus 364: error("sc_read_pubkey failed");
365: key_free(k);
366: return NULL;
367: }
368: return k;
369: }
1.13 jakob 370: #endif /* SMARTCARD */