source: trunk/third/openssh/scard.c @ 22570

Revision 22570, 12.7 KB checked in by ghudson, 17 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22569, which included commits to RCS files with non-trunk default branches.
Line 
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#if defined(SMARTCARD) && defined(USE_SECTOK)
27RCSID("$OpenBSD: scard.c,v 1.29 2004/05/08 00:21:31 djm Exp $");
28
29#include <openssl/evp.h>
30#include <sectok.h>
31
32#include "key.h"
33#include "log.h"
34#include "xmalloc.h"
35#include "misc.h"
36#include "scard.h"
37
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
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
59u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
60
61static int sc_fd = -1;
62static char *sc_reader_id = NULL;
63static char *sc_pin = NULL;
64static int cla = 0x00;  /* class */
65
66static void sc_mk_digest(const char *pin, u_char *digest);
67static int get_AUT0(u_char *aut0);
68static int try_AUT0(void);
69
70/* interface to libsectok */
71
72static int
73sc_open(void)
74{
75        int sw;
76
77        if (sc_fd >= 0)
78                return sc_fd;
79
80        sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
81        if (sc_fd < 0) {
82                error("sectok_open failed: %s", sectok_get_sw(sw));
83                return SCARD_ERROR_FAIL;
84        }
85        if (! sectok_cardpresent(sc_fd)) {
86                debug("smartcard in reader %s not present, skipping",
87                    sc_reader_id);
88                sc_close();
89                return SCARD_ERROR_NOCARD;
90        }
91        if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
92                error("sectok_reset failed: %s", sectok_get_sw(sw));
93                sc_fd = -1;
94                return SCARD_ERROR_FAIL;
95        }
96        if ((cla = cyberflex_inq_class(sc_fd)) < 0)
97                cla = 0;
98
99        debug("sc_open ok %d", sc_fd);
100        return sc_fd;
101}
102
103static int
104sc_enable_applet(void)
105{
106        static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
107        int sw = 0;
108
109        /* select applet id */
110        sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
111        if (!sectok_swOK(sw)) {
112                error("sectok_apdu failed: %s", sectok_get_sw(sw));
113                sc_close();
114                return -1;
115        }
116        return 0;
117}
118
119static int
120sc_init(void)
121{
122        int status;
123
124        status = sc_open();
125        if (status == SCARD_ERROR_NOCARD) {
126                return SCARD_ERROR_NOCARD;
127        }
128        if (status < 0 ) {
129                error("sc_open failed");
130                return status;
131        }
132        if (sc_enable_applet() < 0) {
133                error("sc_enable_applet failed");
134                return SCARD_ERROR_APPLET;
135        }
136        return 0;
137}
138
139static int
140sc_read_pubkey(Key * k)
141{
142        u_char buf[2], *n;
143        char *p;
144        int len, sw, status = -1;
145
146        len = sw = 0;
147        n = NULL;
148
149        if (sc_fd < 0) {
150                if (sc_init() < 0)
151                        goto err;
152        }
153
154        /* get key size */
155        sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
156            sizeof(buf), buf, &sw);
157        if (!sectok_swOK(sw)) {
158                error("could not obtain key length: %s", sectok_get_sw(sw));
159                goto err;
160        }
161        len = (buf[0] << 8) | buf[1];
162        len /= 8;
163        debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
164
165        n = xmalloc(len);
166        /* get n */
167        sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
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        }
174        if (!sectok_swOK(sw)) {
175                error("could not obtain public key: %s", sectok_get_sw(sw));
176                goto err;
177        }
178
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");
183                goto err;
184        }
185
186        /* currently the java applet just stores 'n' */
187        if (!BN_set_word(k->rsa->e, 35)) {
188                error("c_read_pubkey: BN_set_word(e, 35) failed");
189                goto err;
190        }
191
192        status = 0;
193        p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
194        debug("fingerprint %u %s", key_size(k), p);
195        xfree(p);
196
197err:
198        if (n != NULL)
199                xfree(n);
200        sc_close();
201        return status;
202}
203
204/* private key operations */
205
206static int
207sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
208    int padding)
209{
210        u_char *padded = NULL;
211        int sw, len, olen, status = -1;
212
213        debug("sc_private_decrypt called");
214
215        olen = len = sw = 0;
216        if (sc_fd < 0) {
217                status = sc_init();
218                if (status < 0 )
219                        goto err;
220        }
221        if (padding != RSA_PKCS1_PADDING)
222                goto err;
223
224        len = BN_num_bytes(rsa->n);
225        padded = xmalloc(len);
226
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);
233        }
234        if (!sectok_swOK(sw)) {
235                error("sc_private_decrypt: INS_DECRYPT failed: %s",
236                    sectok_get_sw(sw));
237                goto err;
238        }
239        olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
240            len);
241err:
242        if (padded)
243                xfree(padded);
244        sc_close();
245        return (olen >= 0 ? olen : status);
246}
247
248static int
249sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
250    int padding)
251{
252        u_char *padded = NULL;
253        int sw, len, status = -1;
254
255        len = sw = 0;
256        if (sc_fd < 0) {
257                status = sc_init();
258                if (status < 0 )
259                        goto err;
260        }
261        if (padding != RSA_PKCS1_PADDING)
262                goto err;
263
264        debug("sc_private_encrypt called");
265        len = BN_num_bytes(rsa->n);
266        padded = xmalloc(len);
267
268        if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) {
269                error("RSA_padding_add_PKCS1_type_1 failed");
270                goto err;
271        }
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);
277        }
278        if (!sectok_swOK(sw)) {
279                error("sc_private_encrypt: INS_DECRYPT failed: %s",
280                    sectok_get_sw(sw));
281                goto err;
282        }
283err:
284        if (padded)
285                xfree(padded);
286        sc_close();
287        return (len >= 0 ? len : status);
288}
289
290/* called on free */
291
292static int (*orig_finish)(RSA *rsa) = NULL;
293
294static int
295sc_finish(RSA *rsa)
296{
297        if (orig_finish)
298                orig_finish(rsa);
299        sc_close();
300        return 1;
301}
302
303/* engine for overloading private key operations */
304
305static RSA_METHOD *
306sc_get_rsa_method(void)
307{
308        static RSA_METHOD smart_rsa;
309        const RSA_METHOD *def = RSA_get_default_method();
310
311        /* use the OpenSSL version */
312        memcpy(&smart_rsa, def, sizeof(smart_rsa));
313
314        smart_rsa.name          = "sectok";
315
316        /* overload */
317        smart_rsa.rsa_priv_enc  = sc_private_encrypt;
318        smart_rsa.rsa_priv_dec  = sc_private_decrypt;
319
320        /* save original */
321        orig_finish             = def->finish;
322        smart_rsa.finish        = sc_finish;
323
324        return &smart_rsa;
325}
326
327#ifdef USE_ENGINE
328static ENGINE *
329sc_get_engine(void)
330{
331        static ENGINE *smart_engine = NULL;
332
333        if ((smart_engine = ENGINE_new()) == NULL)
334                fatal("ENGINE_new failed");
335
336        ENGINE_set_id(smart_engine, "sectok");
337        ENGINE_set_name(smart_engine, "libsectok");
338
339        ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
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}
347#endif
348
349void
350sc_close(void)
351{
352        if (sc_fd >= 0) {
353                sectok_close(sc_fd);
354                sc_fd = -1;
355        }
356}
357
358Key **
359sc_get_keys(const char *id, const char *pin)
360{
361        Key *k, *n, **keys;
362        int status, nkeys = 2;
363
364        if (sc_reader_id != NULL)
365                xfree(sc_reader_id);
366        sc_reader_id = xstrdup(id);
367
368        if (sc_pin != NULL)
369                xfree(sc_pin);
370        sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
371
372        k = key_new(KEY_RSA);
373        if (k == NULL) {
374                return NULL;
375        }
376        status = sc_read_pubkey(k);
377        if (status == SCARD_ERROR_NOCARD) {
378                key_free(k);
379                return NULL;
380        }
381        if (status < 0 ) {
382                error("sc_read_pubkey failed");
383                key_free(k);
384                return NULL;
385        }
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
418static void
419sc_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
429static int
430get_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
447static int
448try_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
473int
474sc_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        logit("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        logit("cyberflex_load_rsa_pub done");
540        status = 0;
541
542done:
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);
556}
557
558char *
559sc_get_key_label(Key *key)
560{
561        return xstrdup("smartcard key");
562}
563
564#endif /* SMARTCARD && USE_SECTOK */
Note: See TracBrowser for help on using the repository browser.