]> andersk Git - openssh.git/blob - scard.c
1d54df86fae93e87691250df6222117e6171ccc8
[openssh.git] / scard.c
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 #include "includes.h"
26 #ifdef SMARTCARD
27 RCSID("$OpenBSD: scard.c,v 1.18 2002/03/21 16:38:06 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 #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
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;
55 static char *sc_reader_id = NULL;
56 static int cla = 0x00;  /* class */
57
58 /* interface to libsectok */
59
60 static int
61 sc_open(void)
62 {
63         int sw;
64
65         if (sc_fd >= 0)
66                 return sc_fd;
67
68         sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
69         if (sc_fd < 0) {
70                 error("sectok_open failed: %s", sectok_get_sw(sw));
71                 return SCARD_ERROR_FAIL;
72         }
73         if (! sectok_cardpresent(sc_fd)) {
74                 debug("smartcard in reader %s not present, skipping",
75                     sc_reader_id);
76                 sc_close();
77                 return SCARD_ERROR_NOCARD;
78         }
79         if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
80                 error("sectok_reset failed: %s", sectok_get_sw(sw));
81                 sc_fd = -1;
82                 return SCARD_ERROR_FAIL;
83         }
84         if ((cla = cyberflex_inq_class(sc_fd)) < 0)
85                 cla = 0;
86
87         debug("sc_open ok %d", sc_fd);
88         return sc_fd;
89 }
90
91 static int
92 sc_enable_applet(void)
93 {
94         static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
95         int sw = 0;
96
97         /* select applet id */
98         sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
99         if (!sectok_swOK(sw)) {
100                 error("sectok_apdu failed: %s", sectok_get_sw(sw));
101                 sc_close();
102                 return -1;
103         }
104         return 0;
105 }
106
107 static int
108 sc_init(void)
109 {
110         int status;
111
112         status = sc_open();
113         if (status == SCARD_ERROR_NOCARD) {
114                 return SCARD_ERROR_NOCARD;
115         }
116         if (status < 0 ) {
117                 error("sc_open failed");
118                 return status;
119         }
120         if (sc_enable_applet() < 0) {
121                 error("sc_enable_applet failed");
122                 return SCARD_ERROR_APPLET;
123         }
124         return 0;
125 }
126
127 static int
128 sc_read_pubkey(Key * k)
129 {
130         u_char buf[2], *n;
131         char *p;
132         int len, sw, status = -1;
133
134         len = sw = 0;
135         n = NULL;
136
137         if (sc_fd < 0) {
138                 status = sc_init();
139                 if (status < 0 )
140                         goto err;
141         }
142
143         /* get key size */
144         sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
145             sizeof(buf), buf, &sw);
146         if (!sectok_swOK(sw)) {
147                 error("could not obtain key length: %s", sectok_get_sw(sw));
148                 goto err;
149         }
150         len = (buf[0] << 8) | buf[1];
151         len /= 8;
152         debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
153
154         n = xmalloc(len);
155         /* get n */
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));
159                 goto err;
160         }
161
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");
166                 goto err;
167         }
168
169         /* currently the java applet just stores 'n' */
170         if (!BN_set_word(k->rsa->e, 35)) {
171                 error("c_read_pubkey: BN_set_word(e, 35) failed");
172                 goto err;
173         }
174
175         status = 0;
176         p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
177         debug("fingerprint %d %s", key_size(k), p);
178         xfree(p);
179
180 err:
181         if (n != NULL)
182                 xfree(n);
183         sc_close();
184         return status;
185 }
186
187 /* private key operations */
188
189 static int
190 sc_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
191     int padding)
192 {
193         u_char *padded = NULL;
194         int sw, len, olen, status = -1;
195
196         debug("sc_private_decrypt called");
197
198         olen = len = sw = 0;
199         if (sc_fd < 0) {
200                 status = sc_init();
201                 if (status < 0 )
202                         goto err;
203         }
204         if (padding != RSA_PKCS1_PADDING)
205                 goto err;
206
207         len = BN_num_bytes(rsa->n);
208         padded = xmalloc(len);
209
210         sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, (u_char *)from,
211             0, NULL, &sw);
212         if (!sectok_swOK(sw)) {
213                 error("sc_private_decrypt: INS_DECRYPT failed: %s",
214                     sectok_get_sw(sw));
215                 goto err;
216         }
217         sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
218             len, padded, &sw);
219         if (!sectok_swOK(sw)) {
220                 error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
221                     sectok_get_sw(sw));
222                 goto err;
223         }
224         olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
225             len);
226 err:
227         if (padded)
228                 xfree(padded);
229         sc_close();
230         return (olen >= 0 ? olen : status);
231 }
232
233 static int
234 sc_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
235     int padding)
236 {
237         u_char *padded = NULL;
238         int sw, len, status = -1;
239
240         len = sw = 0;
241         if (sc_fd < 0) {
242                 status = sc_init();
243                 if (status < 0 )
244                         goto err;
245         }
246         if (padding != RSA_PKCS1_PADDING)
247                 goto err;
248
249         debug("sc_private_encrypt called");
250         len = BN_num_bytes(rsa->n);
251         padded = xmalloc(len);
252
253         if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) {
254                 error("RSA_padding_add_PKCS1_type_1 failed");
255                 goto err;
256         }
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,
264             len, to, &sw);
265         if (!sectok_swOK(sw)) {
266                 error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
267                     sectok_get_sw(sw));
268                 goto err;
269         }
270 err:
271         if (padded)
272                 xfree(padded);
273         sc_close();
274         return (len >= 0 ? len : status);
275 }
276
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
291 /* engine for overloading private key operations */
292
293 static ENGINE *smart_engine = NULL;
294 static RSA_METHOD smart_rsa;
295
296 ENGINE *
297 sc_get_engine(void)
298 {
299         const RSA_METHOD *def;
300
301         def = RSA_get_default_openssl_method();
302
303         /* use the OpenSSL version */
304         memcpy(&smart_rsa, def, sizeof(smart_rsa));
305
306         smart_rsa.name          = "sectok";
307
308         /* overload */
309         smart_rsa.rsa_priv_enc  = sc_private_encrypt;
310         smart_rsa.rsa_priv_dec  = sc_private_decrypt;
311
312         /* save original */
313         orig_finish             = def->finish;
314         smart_rsa.finish        = sc_finish;
315
316         if ((smart_engine = ENGINE_new()) == NULL)
317                 fatal("ENGINE_new failed");
318
319         ENGINE_set_id(smart_engine, "sectok");
320         ENGINE_set_name(smart_engine, "libsectok");
321
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 void
332 sc_close(void)
333 {
334         if (sc_fd >= 0) {
335                 sectok_close(sc_fd);
336                 sc_fd = -1;
337         }
338 }
339
340 Key *
341 sc_get_key(const char *id)
342 {
343         Key *k;
344         int status;
345
346         if (sc_reader_id != NULL)
347                 xfree(sc_reader_id);
348         sc_reader_id = xstrdup(id);
349
350         k = key_new(KEY_RSA);
351         if (k == NULL) {
352                 return NULL;
353         }
354         status = sc_read_pubkey(k);
355         if (status == SCARD_ERROR_NOCARD) {
356                 key_free(k);
357                 return NULL;
358         }
359         if (status < 0 ) {
360                 error("sc_read_pubkey failed");
361                 key_free(k);
362                 return NULL;
363         }
364         return k;
365 }
366 #endif /* SMARTCARD */
This page took 0.049605 seconds and 3 git commands to generate.