]> andersk Git - openssh.git/blame - scard.c
- OpenBSD CVS Sync
[openssh.git] / scard.c
CommitLineData
637b033d 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"
27RCSID("$OpenBSD: scard.c,v 1.4 2001/07/02 22:40:17 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#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
45static int sc_fd = -1;
46static int sc_reader_num = 0;
47static int cla = 0x00; /* class */
48
49/* interface to libsectok */
50
51static int
52sc_open(int num)
53{
54 u_char atr[256];
55 int sw;
56
57 if (sc_fd >= 0)
58 return sc_fd;
59 sc_reader_num = num;
60
61 sc_fd = sectok_open(sc_reader_num, 0, NULL);
62 if (sc_fd < 0) {
63 error("sectok_open failed %d", sc_fd);
64 return sc_fd;
65 }
66 if (sectok_reset(sc_fd, 0, atr, &sw) <= 0) {
67 error("sectok_reset failed: %s", sectok_get_sw(sw));
68 sc_fd = -1;
69 return sc_fd;
70 }
71 debug("sc_open ok %d", sc_fd);
72 return sc_fd;
73}
74
75static int
76sc_enable_applet(void)
77{
78 u_char contID[2], aid[MAX_BUF_SIZE];
79 int i, len, sw, aid_len;
80
81 len = sw = 0;
82 contID[0] = 0x77;
83 contID[1] = 0x78;
84
85 if (sectok_selectfile(sc_fd, cla, root_fid, &sw) < 0) {
86 error("sectok_selectfile root_fid failed: %s",
87 sectok_get_sw(sw));
88 return -1;
89 }
90 if (sectok_selectfile(sc_fd, cla, contID, &sw) < 0) {
91 error("sectok_selectfile failed: %s", sectok_get_sw(sw));
92 return -1;
93 }
94 /* send appled id */
95 for (i = 0; i < sizeof(aid); i++)
96 aid[i] = 0x77;
97 aid_len = 5;
98 sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, aid_len, aid, 0, NULL, &sw);
99 if (!sectok_swOK(sw)) {
100 error("sectok_apdu failed: %s", sectok_get_sw(sw));
101 return -1;
102 }
103 return 0;
104}
105
106static int
107sc_read_pubkey(Key * k)
108{
109 u_char buf[2], *n;
110 char *p;
111 int len, sw;
112
113 len = sw = 0;
114
115 /* get key size */
116 sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
117 sizeof(buf), buf, &sw);
118 if (!sectok_swOK(sw)) {
119 error("could not obtain key length: %s", sectok_get_sw(sw));
120 return -1;
121 }
122 len = (buf[0] << 8) | buf[1];
123 len /= 8;
124 debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
125
126 n = xmalloc(len);
127 /* get n */
128 sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
129 if (!sectok_swOK(sw)) {
130 error("could not obtain public key: %s", sectok_get_sw(sw));
131 xfree(n);
132 return -1;
133 }
134 debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
135
136 if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
137 error("c_read_pubkey: BN_bin2bn failed");
138 xfree(n);
139 return -1;
140 }
141 xfree(n);
142
143 /* currently the java applet just stores 'n' */
144 if (!BN_set_word(k->rsa->e, 35)) {
145 error("c_read_pubkey: BN_set_word(e, 35) failed");
146 return -1;
147 }
148
149 p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
150 debug("fingerprint %d %s", key_size(k), p);
151 xfree(p);
152
153 return 0;
154}
155
156/* private key operations */
157
158static int
159sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
160{
161 u_char *padded = NULL;
162 int sw, len, olen;
163
164 debug("sc_private_decrypt called");
165
166 olen = len = sw = 0;
167 if (padding != RSA_PKCS1_PADDING)
168 goto err;
169
170 len = BN_num_bytes(rsa->n);
171 padded = xmalloc(len);
172
173 sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, 0, NULL, &sw);
174 if (!sectok_swOK(sw)) {
175 error("sc_private_decrypt: INS_DECRYPT failed: %s",
176 sectok_get_sw(sw));
177 goto err;
178 }
179 sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
180 len, padded, &sw);
181 if (!sectok_swOK(sw)) {
182 error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
183 sectok_get_sw(sw));
184 goto err;
185 }
186 olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
187 len);
188err:
189 if (padded)
190 xfree(padded);
191 return olen;
192}
193
194static int
195sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, int padding)
196{
197 u_char *padded = NULL;
198 int sw, len;
199
200 len = sw = 0;
201 if (padding != RSA_PKCS1_PADDING)
202 goto err;
203
204 debug("sc_private_encrypt called");
205 len = BN_num_bytes(rsa->n);
206 padded = xmalloc(len);
207
208 if (RSA_padding_add_PKCS1_type_1(padded, len, from, flen) <= 0) {
209 error("RSA_padding_add_PKCS1_type_1 failed");
210 goto err;
211 }
212 sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, 0, NULL, &sw);
213 if (!sectok_swOK(sw)) {
214 error("sc_private_decrypt: INS_DECRYPT failed: %s",
215 sectok_get_sw(sw));
216 goto err;
217 }
218 sectok_apdu(sc_fd, CLA_SSH, INS_GET_RESPONSE, 0, 0, 0, NULL,
219 len, to, &sw);
220 if (!sectok_swOK(sw)) {
221 error("sc_private_decrypt: INS_GET_RESPONSE failed: %s",
222 sectok_get_sw(sw));
223 goto err;
224 }
225err:
226 if (padded)
227 xfree(padded);
228 return len;
229}
230
231/* engine for overloading private key operations */
232
233static ENGINE *smart_engine = NULL;
234static RSA_METHOD smart_rsa =
235{
236 "sectok",
237 NULL,
238 NULL,
239 NULL,
240 NULL,
241 NULL,
242 NULL,
243 NULL,
244 NULL,
245 0,
246 NULL,
247};
248
249ENGINE *
250sc_get_engine(void)
251{
252 RSA_METHOD *def;
253
254 def = RSA_get_default_openssl_method();
255
256 /* overload */
257 smart_rsa.rsa_priv_enc = sc_private_encrypt;
258 smart_rsa.rsa_priv_dec = sc_private_decrypt;
259
260 /* just use the OpenSSL version */
261 smart_rsa.rsa_pub_enc = def->rsa_pub_enc;
262 smart_rsa.rsa_pub_dec = def->rsa_pub_dec;
263 smart_rsa.rsa_mod_exp = def->rsa_mod_exp;
264 smart_rsa.bn_mod_exp = def->bn_mod_exp;
265 smart_rsa.init = def->init;
266 smart_rsa.finish = def->finish;
267 smart_rsa.flags = def->flags;
268 smart_rsa.app_data = def->app_data;
269 smart_rsa.rsa_sign = def->rsa_sign;
270 smart_rsa.rsa_verify = def->rsa_verify;
271
272 smart_engine = ENGINE_new();
273
274 ENGINE_set_id(smart_engine, "sectok");
275 ENGINE_set_name(smart_engine, "libsectok");
276 ENGINE_set_RSA(smart_engine, &smart_rsa);
277 ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
278 ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
279 ENGINE_set_RAND(smart_engine, RAND_SSLeay());
280 ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
281
282 return smart_engine;
283}
284
285Key *
286sc_get_key(int sc_reader_num)
287{
288 Key *k;
289
290 if (sc_open(sc_reader_num) < 0) {
291 error("sc_open failed");
292 return NULL;
293 }
294 if (sc_enable_applet() < 0) {
295 error("sc_enable_applet failed");
296 return NULL;
297 }
298 k = key_new(KEY_RSA);
299 if (k == NULL) {
300 return NULL;
301 }
302 if (sc_read_pubkey(k) < 0) {
303 error("sc_read_pubkey failed");
304 key_free(k);
305 return NULL;
306 }
307 return k;
308}
309#endif
This page took 0.08364 seconds and 5 git commands to generate.