/src/opensc/src/libopensc/card-cac1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * card-cac1.c: Support for legacy CAC-1 |
3 | | * card-default.c: Support for cards with no driver |
4 | | * |
5 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
6 | | * Copyright (C) 2005,2006,2007,2008,2009,2010 Douglas E. Engert <deengert@anl.gov> |
7 | | * Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning@identityalliance.com> |
8 | | * Copyright (C) 2007, EMC, Russell Larner <rlarner@rsa.com> |
9 | | * Copyright (C) 2016 - 2018, Red Hat, Inc. |
10 | | * |
11 | | * CAC driver author: Robert Relyea <rrelyea@redhat.com> |
12 | | * Further work: Jakub Jelen <jjelen@redhat.com> |
13 | | * |
14 | | * This library is free software; you can redistribute it and/or |
15 | | * modify it under the terms of the GNU Lesser General Public |
16 | | * License as published by the Free Software Foundation; either |
17 | | * version 2.1 of the License, or (at your option) any later version. |
18 | | * |
19 | | * This library is distributed in the hope that it will be useful, |
20 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 | | * Lesser General Public License for more details. |
23 | | * |
24 | | * You should have received a copy of the GNU Lesser General Public |
25 | | * License along with this library; if not, write to the Free Software |
26 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
27 | | */ |
28 | | |
29 | | #ifdef HAVE_CONFIG_H |
30 | | #include "config.h" |
31 | | #endif |
32 | | |
33 | | #include <ctype.h> |
34 | | #include <fcntl.h> |
35 | | #include <limits.h> |
36 | | #include <stdlib.h> |
37 | | #include <string.h> |
38 | | |
39 | | #ifdef _WIN32 |
40 | | #include <io.h> |
41 | | #else |
42 | | #include <unistd.h> |
43 | | #endif |
44 | | |
45 | | #ifdef ENABLE_OPENSSL |
46 | | #include <openssl/sha.h> |
47 | | #endif /* ENABLE_OPENSSL */ |
48 | | |
49 | | #include "internal.h" |
50 | | #include "simpletlv.h" |
51 | | #include "cardctl.h" |
52 | | #include "iso7816.h" |
53 | | #include "card-cac-common.h" |
54 | | #include "pkcs15.h" |
55 | | |
56 | | /* |
57 | | * CAC hardware and APDU constants |
58 | | */ |
59 | 0 | #define CAC_INS_GET_CERTIFICATE 0x36 /* CAC1 command to read a certificate */ |
60 | | |
61 | | /* |
62 | | * OLD cac read certificate, only use with CAC-1 card. |
63 | | */ |
64 | | static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_len) |
65 | 0 | { |
66 | 0 | u8 buf[CAC_MAX_SIZE]; |
67 | 0 | u8 *out_ptr; |
68 | 0 | size_t size = 0; |
69 | 0 | size_t left = 0; |
70 | 0 | size_t len; |
71 | 0 | sc_apdu_t apdu; |
72 | 0 | int r = SC_SUCCESS; |
73 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
74 | | /* get the size */ |
75 | 0 | size = left = *out_buf ? *out_len : sizeof(buf); |
76 | 0 | out_ptr = *out_buf ? *out_buf : buf; |
77 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, CAC_INS_GET_CERTIFICATE, 0, 0 ); |
78 | 0 | len = MIN(left, 100); |
79 | 0 | while (left > 0) { |
80 | 0 | apdu.resp = out_ptr; |
81 | 0 | apdu.le = len; |
82 | 0 | apdu.resplen = left; |
83 | 0 | r = sc_transmit_apdu(card, &apdu); |
84 | 0 | if (r < 0) { |
85 | 0 | break; |
86 | 0 | } |
87 | 0 | if (apdu.resplen == 0) { |
88 | 0 | r = SC_ERROR_INTERNAL; |
89 | 0 | break; |
90 | 0 | } |
91 | | /* in the old CAC-1, 0x63 means 'more data' in addition to 'pin failed' */ |
92 | 0 | if (apdu.sw1 != 0x63 || apdu.sw2 < 1) { |
93 | | /* we've either finished reading, or hit an error, break */ |
94 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
95 | 0 | left -= apdu.resplen; |
96 | 0 | break; |
97 | 0 | } |
98 | | /* Adjust the lengths */ |
99 | 0 | left -= apdu.resplen; |
100 | 0 | out_ptr += apdu.resplen; |
101 | 0 | len = MIN(left, apdu.sw2); |
102 | 0 | } |
103 | 0 | if (r < 0) { |
104 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
105 | 0 | } |
106 | 0 | r = (int)(size - left); |
107 | 0 | if (*out_buf == NULL) { |
108 | 0 | *out_buf = malloc(r); |
109 | 0 | if (*out_buf == NULL) { |
110 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, |
111 | 0 | SC_ERROR_OUT_OF_MEMORY); |
112 | 0 | } |
113 | 0 | memcpy(*out_buf, buf, r); |
114 | 0 | } |
115 | 0 | *out_len = r; |
116 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
117 | 0 | } |
118 | | |
119 | | /* |
120 | | * Callers of this may be expecting a certificate, |
121 | | * select file will have saved the object type for us |
122 | | * as well as set that we want the cert from the object. |
123 | | */ |
124 | | static int cac_read_binary(sc_card_t *card, unsigned int idx, |
125 | | unsigned char *buf, size_t count, unsigned long *flags) |
126 | 0 | { |
127 | 0 | cac_private_data_t * priv = CAC_DATA(card); |
128 | 0 | int r = 0; |
129 | 0 | u8 *val = NULL; |
130 | 0 | u8 *cert_ptr; |
131 | 0 | size_t val_len = 0; |
132 | 0 | size_t len, cert_len; |
133 | 0 | u8 cert_type; |
134 | |
|
135 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
136 | | |
137 | | /* if we didn't return it all last time, return the remainder */ |
138 | 0 | if (priv->cached) { |
139 | 0 | sc_log(card->ctx, |
140 | 0 | "returning cached value idx=%d count=%"SC_FORMAT_LEN_SIZE_T"u", |
141 | 0 | idx, count); |
142 | 0 | if (idx > priv->cache_buf_len) { |
143 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_FILE_END_REACHED); |
144 | 0 | } |
145 | 0 | len = MIN(count, priv->cache_buf_len-idx); |
146 | 0 | memcpy(buf, &priv->cache_buf[idx], len); |
147 | 0 | LOG_FUNC_RETURN(card->ctx, (int)len); |
148 | 0 | } |
149 | | |
150 | 0 | sc_log(card->ctx, |
151 | 0 | "clearing cache idx=%d count=%"SC_FORMAT_LEN_SIZE_T"u", |
152 | 0 | idx, count); |
153 | 0 | free(priv->cache_buf); |
154 | 0 | priv->cache_buf = NULL; |
155 | 0 | priv->cache_buf_len = 0; |
156 | |
|
157 | 0 | r = cac_cac1_get_certificate(card, &val, &val_len); |
158 | 0 | if (r < 0) |
159 | 0 | goto done; |
160 | 0 | if (val_len < 1) { |
161 | 0 | r = SC_ERROR_INVALID_DATA; |
162 | 0 | goto done; |
163 | 0 | } |
164 | | |
165 | 0 | cert_type = val[0]; |
166 | 0 | cert_ptr = val + 1; |
167 | 0 | cert_len = val_len - 1; |
168 | | |
169 | | /* if the info byte is 1, then the cert is compressed, decompress it */ |
170 | 0 | if ((cert_type & 0x3) == 1) { |
171 | 0 | *flags |= SC_FILE_FLAG_COMPRESSED_AUTO; |
172 | 0 | } |
173 | 0 | if (cert_len > 0) { |
174 | 0 | priv->cache_buf = malloc(cert_len); |
175 | 0 | if (priv->cache_buf == NULL) { |
176 | 0 | r = SC_ERROR_OUT_OF_MEMORY; |
177 | 0 | goto done; |
178 | 0 | } |
179 | 0 | priv->cache_buf_len = cert_len; |
180 | 0 | memcpy(priv->cache_buf, cert_ptr, cert_len); |
181 | 0 | } |
182 | | |
183 | | /* OK we've read the data, now copy the required portion out to the callers buffer */ |
184 | 0 | priv->cached = 1; |
185 | 0 | len = MIN(count, priv->cache_buf_len-idx); |
186 | 0 | if (len && priv->cache_buf) |
187 | 0 | memcpy(buf, &priv->cache_buf[idx], len); |
188 | 0 | r = (int)len; |
189 | 0 | done: |
190 | 0 | if (val) |
191 | 0 | free(val); |
192 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
193 | 0 | } |
194 | | |
195 | | /* |
196 | | * CAC cards use SC_PATH_SELECT_OBJECT_ID rather than SC_PATH_SELECT_FILE_ID. In order to use more |
197 | | * of the PKCS #15 structure, we call the selection SC_PATH_SELECT_FILE_ID, but we set p1 to 2 instead |
198 | | * of 0. Also cac1 does not do any FCI, but it doesn't understand not selecting it. It returns invalid INS |
199 | | * if it doesn't like anything about the select, so we always 'request' FCI for CAC1 |
200 | | * |
201 | | * The rest is just copied from iso7816_select_file |
202 | | */ |
203 | | static int cac_select_file_by_type(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) |
204 | 0 | { |
205 | 0 | struct sc_context *ctx; |
206 | 0 | struct sc_apdu apdu; |
207 | 0 | unsigned char buf[SC_MAX_APDU_BUFFER_SIZE]; |
208 | 0 | unsigned char pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf; |
209 | 0 | int r, pathtype; |
210 | 0 | size_t pathlen; |
211 | 0 | struct sc_file *file = NULL; |
212 | 0 | cac_private_data_t * priv = CAC_DATA(card); |
213 | |
|
214 | 0 | assert(card != NULL && in_path != NULL); |
215 | 0 | ctx = card->ctx; |
216 | |
|
217 | 0 | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
218 | |
|
219 | 0 | memcpy(path, in_path->value, in_path->len); |
220 | 0 | pathlen = in_path->len; |
221 | 0 | pathtype = in_path->type; |
222 | |
|
223 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, |
224 | 0 | "path=%s, path->value=%s path->type=%d (%x)", |
225 | 0 | sc_print_path(in_path), |
226 | 0 | sc_dump_hex(in_path->value, in_path->len), |
227 | 0 | in_path->type, in_path->type); |
228 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "file_out=%p index=%d count=%d\n", |
229 | 0 | file_out, in_path->index, in_path->count); |
230 | | |
231 | | /* Sigh, iso7816_select_file expects paths to keys to have specific |
232 | | * formats. There is no override. We have to add some bytes to the |
233 | | * path to make it happy. |
234 | | * We only need to do this for private keys. |
235 | | */ |
236 | 0 | if ((pathlen > 2) && (pathlen <= 4) && memcmp(path, "\x3F\x00", 2) == 0) { |
237 | 0 | path += 2; |
238 | 0 | pathlen -= 2; |
239 | 0 | } |
240 | | |
241 | | |
242 | | /* CAC has multiple different type of objects that aren't PKCS #15. When we read |
243 | | * them we need convert them to something PKCS #15 would understand. Find the object |
244 | | * and object type here: |
245 | | */ |
246 | 0 | if (priv) { /* don't record anything if we haven't been initialized yet */ |
247 | | /* forget any old cached values */ |
248 | 0 | if (priv->cache_buf) { |
249 | 0 | free(priv->cache_buf); |
250 | 0 | priv->cache_buf = NULL; |
251 | 0 | } |
252 | 0 | priv->cache_buf_len = 0; |
253 | 0 | priv->cached = 0; |
254 | 0 | } |
255 | |
|
256 | 0 | if (in_path->aid.len) { |
257 | 0 | if (!pathlen) { |
258 | 0 | memcpy(path, in_path->aid.value, in_path->aid.len); |
259 | 0 | pathlen = in_path->aid.len; |
260 | 0 | pathtype = SC_PATH_TYPE_DF_NAME; |
261 | 0 | } else { |
262 | | /* First, select the application */ |
263 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,"select application" ); |
264 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 4, 0); |
265 | 0 | apdu.data = in_path->aid.value; |
266 | 0 | apdu.datalen = in_path->aid.len; |
267 | 0 | apdu.lc = in_path->aid.len; |
268 | |
|
269 | 0 | r = sc_transmit_apdu(card, &apdu); |
270 | 0 | LOG_TEST_RET(ctx, r, "APDU transmit failed"); |
271 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
272 | 0 | if (r) |
273 | 0 | LOG_FUNC_RETURN(ctx, r); |
274 | |
|
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0); |
279 | |
|
280 | 0 | switch (pathtype) { |
281 | | /* ideally we would had SC_PATH_TYPE_OBJECT_ID and add code to the iso7816 select. |
282 | | * Unfortunately we'd also need to update the caching code as well. For now just |
283 | | * use FILE_ID and change p1 here */ |
284 | 0 | case SC_PATH_TYPE_FILE_ID: |
285 | 0 | apdu.p1 = 2; |
286 | 0 | if (pathlen != 2) |
287 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
288 | 0 | break; |
289 | 0 | case SC_PATH_TYPE_DF_NAME: |
290 | 0 | apdu.p1 = 4; |
291 | 0 | break; |
292 | 0 | default: |
293 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
294 | 0 | } |
295 | 0 | apdu.lc = pathlen; |
296 | 0 | apdu.data = path; |
297 | 0 | apdu.datalen = pathlen; |
298 | 0 | apdu.resp = buf; |
299 | 0 | apdu.resplen = sizeof(buf); |
300 | 0 | apdu.le = sc_get_max_recv_size(card) < 256 ? sc_get_max_recv_size(card) : 256; |
301 | 0 | apdu.p2 = 0x00; |
302 | |
|
303 | 0 | r = sc_transmit_apdu(card, &apdu); |
304 | 0 | LOG_TEST_RET(ctx, r, "APDU transmit failed"); |
305 | | |
306 | 0 | if (file_out == NULL) { |
307 | | /* For some cards 'SELECT' can be only with request to return FCI/FCP. */ |
308 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
309 | 0 | if (apdu.sw1 == 0x6A && apdu.sw2 == 0x86) { |
310 | 0 | apdu.p2 = 0x00; |
311 | 0 | apdu.resplen = sizeof(buf); |
312 | 0 | if (sc_transmit_apdu(card, &apdu) == SC_SUCCESS) |
313 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
314 | 0 | } |
315 | 0 | if (apdu.sw1 == 0x61) |
316 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
317 | 0 | LOG_FUNC_RETURN(ctx, r); |
318 | 0 | } |
319 | | |
320 | 0 | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
321 | 0 | if (r) |
322 | 0 | LOG_FUNC_RETURN(ctx, r); |
323 | | |
324 | | /* CAC cards never return FCI, fake one */ |
325 | 0 | file = sc_file_new(); |
326 | 0 | if (file == NULL) |
327 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
328 | 0 | file->path = *in_path; |
329 | 0 | file->size = CAC_MAX_SIZE; /* we don't know how big, just give a large size until we can read the file */ |
330 | |
|
331 | 0 | *file_out = file; |
332 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
333 | |
|
334 | 0 | } |
335 | | |
336 | | static int cac_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) |
337 | 0 | { |
338 | 0 | return cac_select_file_by_type(card, in_path, file_out); |
339 | 0 | } |
340 | | |
341 | | static int cac_finish(sc_card_t *card) |
342 | 0 | { |
343 | 0 | cac_private_data_t * priv = CAC_DATA(card); |
344 | |
|
345 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
346 | 0 | if (priv) { |
347 | 0 | cac_free_private_data(priv); |
348 | 0 | } |
349 | 0 | return SC_SUCCESS; |
350 | 0 | } |
351 | | |
352 | | |
353 | | /* select a CAC pki applet by index */ |
354 | | static int cac_select_pki_applet(sc_card_t *card, int index) |
355 | 0 | { |
356 | 0 | sc_path_t applet_path = cac_cac_pki_obj.path; |
357 | 0 | applet_path.aid.value[applet_path.aid.len-1] = index; |
358 | 0 | return cac_select_file_by_type(card, &applet_path, NULL); |
359 | 0 | } |
360 | | |
361 | | /* |
362 | | * Find the first existing CAC applet. If none found, then this isn't a CAC |
363 | | */ |
364 | | static int cac_find_first_pki_applet(sc_card_t *card, int *index_out) |
365 | 0 | { |
366 | 0 | int r, i; |
367 | |
|
368 | 0 | for (i = 0; i < MAX_CAC_SLOTS; i++) { |
369 | 0 | r = cac_select_pki_applet(card, i); |
370 | 0 | if (r == SC_SUCCESS) { |
371 | 0 | u8 data[2]; |
372 | 0 | sc_apdu_t apdu; |
373 | | |
374 | | /* Try to read first two bytes of the buffer to |
375 | | * make sure it is not just malfunctioning card |
376 | | */ |
377 | 0 | sc_format_apdu(card, &apdu, SC_APDU_CASE_2, |
378 | 0 | CAC_INS_GET_CERTIFICATE, 0x00, 0x00); |
379 | 0 | apdu.le = 0x02; |
380 | 0 | apdu.resplen = 2; |
381 | 0 | apdu.resp = data; |
382 | 0 | r = sc_transmit_apdu(card, &apdu); |
383 | | /* SW1 = 0x63 means more data in CAC1 */ |
384 | 0 | if (r == SC_SUCCESS && apdu.sw1 != 0x63) |
385 | 0 | continue; |
386 | | |
387 | 0 | *index_out = i; |
388 | 0 | return SC_SUCCESS; |
389 | 0 | } |
390 | 0 | } |
391 | 0 | return SC_ERROR_OBJECT_NOT_FOUND; |
392 | 0 | } |
393 | | |
394 | | static int cac_populate_cac1(sc_card_t *card, int index, cac_private_data_t *priv) |
395 | 0 | { |
396 | 0 | int r, i; |
397 | 0 | cac_object_t pki_obj = cac_cac_pki_obj; |
398 | 0 | u8 buf[100]; |
399 | 0 | u8 *val; |
400 | 0 | size_t val_len; |
401 | | |
402 | | /* populate PKI objects */ |
403 | 0 | for (i = index; i < MAX_CAC_SLOTS; i++) { |
404 | 0 | r = cac_select_pki_applet(card, i); |
405 | 0 | if (r == SC_SUCCESS) { |
406 | 0 | pki_obj.name = get_cac_label(i); |
407 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, |
408 | 0 | "CAC: pki_object found, cert_next=%d (%s)", |
409 | 0 | i, pki_obj.name); |
410 | 0 | pki_obj.path.aid.value[pki_obj.path.aid.len-1] = i; |
411 | 0 | pki_obj.fd = i+1; /* don't use id of zero */ |
412 | 0 | cac_add_object_to_list(&priv->pki_list, &pki_obj); |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | | /* |
417 | | * create a cuid to simulate the cac 2 cuid. |
418 | | */ |
419 | 0 | priv->cuid = cac_cac_cuid; |
420 | | /* create a serial number by hashing the first 100 bytes of the |
421 | | * first certificate on the card */ |
422 | 0 | r = cac_select_pki_applet(card, index); |
423 | 0 | if (r < 0) { |
424 | 0 | return r; /* shouldn't happen unless the card has been removed or is malfunctioning */ |
425 | 0 | } |
426 | 0 | val = buf; |
427 | 0 | val_len = sizeof(buf); |
428 | 0 | r = cac_cac1_get_certificate(card, &val, &val_len); |
429 | 0 | if (r >= 0) { |
430 | 0 | priv->cac_id = malloc(20); |
431 | 0 | if (priv->cac_id == NULL) { |
432 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
433 | 0 | } |
434 | 0 | #ifdef ENABLE_OPENSSL |
435 | 0 | SHA1(val, val_len, priv->cac_id); |
436 | 0 | priv->cac_id_len = 20; |
437 | 0 | sc_debug_hex(card->ctx, SC_LOG_DEBUG_VERBOSE, |
438 | 0 | "cuid", priv->cac_id, priv->cac_id_len); |
439 | | #else |
440 | | sc_log(card->ctx, "OpenSSL Required"); |
441 | | return SC_ERROR_NOT_SUPPORTED; |
442 | | #endif /* ENABLE_OPENSSL */ |
443 | 0 | } |
444 | 0 | return SC_SUCCESS; |
445 | 0 | } |
446 | | |
447 | | /* |
448 | | * Look for a CAC card. If it exists, initialize our data structures |
449 | | */ |
450 | | static int cac_find_and_initialize(sc_card_t *card, int initialize) |
451 | 0 | { |
452 | 0 | int r, index; |
453 | 0 | cac_private_data_t *priv = NULL; |
454 | | |
455 | | /* already initialized? */ |
456 | 0 | if (card->drv_data) { |
457 | 0 | return SC_SUCCESS; |
458 | 0 | } |
459 | | |
460 | | /* is this a CAC Alt token without any accompanying structures */ |
461 | 0 | r = cac_find_first_pki_applet(card, &index); |
462 | 0 | if (r == SC_SUCCESS) { |
463 | 0 | sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "PKI applet found, is bare CAC-1"); |
464 | 0 | if (!initialize) /* match card only */ |
465 | 0 | return r; |
466 | | |
467 | 0 | if (!priv) { |
468 | 0 | priv = cac_new_private_data(); |
469 | 0 | if (!priv) |
470 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
471 | 0 | } |
472 | 0 | card->drv_data = priv; /* needed for the read_binary() */ |
473 | 0 | r = cac_populate_cac1(card, index, priv); |
474 | 0 | if (r == SC_SUCCESS) { |
475 | 0 | card->type = SC_CARD_TYPE_CAC_I; |
476 | 0 | return r; |
477 | 0 | } |
478 | 0 | card->drv_data = NULL; /* reset on failure */ |
479 | 0 | } |
480 | 0 | if (priv) { |
481 | 0 | cac_free_private_data(priv); |
482 | 0 | } |
483 | 0 | return r; |
484 | 0 | } |
485 | | |
486 | | |
487 | | /* NOTE: returns a bool, 1 card matches, 0 it does not */ |
488 | | static int cac_match_card(sc_card_t *card) |
489 | 0 | { |
490 | 0 | int r; |
491 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
492 | |
|
493 | 0 | r = cac_find_and_initialize(card, 0); |
494 | 0 | return (r == SC_SUCCESS); /* never match */ |
495 | 0 | } |
496 | | |
497 | | |
498 | | static int cac_init(sc_card_t *card) |
499 | 0 | { |
500 | 0 | int r; |
501 | 0 | unsigned long flags; |
502 | |
|
503 | 0 | SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); |
504 | |
|
505 | 0 | r = cac_find_and_initialize(card, 1); |
506 | 0 | if (r < 0) { |
507 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); |
508 | 0 | } |
509 | 0 | flags = SC_ALGORITHM_RSA_RAW; |
510 | |
|
511 | 0 | _sc_card_add_rsa_alg(card, 1024, flags, 0); /* mandatory */ |
512 | 0 | _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ |
513 | 0 | _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ |
514 | |
|
515 | 0 | card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO; |
516 | |
|
517 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
518 | 0 | } |
519 | | |
520 | | static int cac_logout(sc_card_t *card) |
521 | 0 | { |
522 | 0 | int index; |
523 | 0 | return cac_find_first_pki_applet(card, &index); |
524 | 0 | } |
525 | | |
526 | | static struct sc_card_operations cac_ops; |
527 | | |
528 | | static struct sc_card_driver cac1_drv = { |
529 | | "Common Access Card (CAC 1)", |
530 | | "cac1", |
531 | | &cac_ops, |
532 | | NULL, 0, NULL |
533 | | }; |
534 | | |
535 | | static struct sc_card_driver * sc_get_driver(void) |
536 | 0 | { |
537 | | /* Inherit most of the things from the CAC driver */ |
538 | 0 | struct sc_card_driver *cac_drv = sc_get_cac_driver(); |
539 | |
|
540 | 0 | cac_ops = *cac_drv->ops; |
541 | 0 | cac_ops.match_card = cac_match_card; |
542 | 0 | cac_ops.init = cac_init; |
543 | 0 | cac_ops.finish = cac_finish; |
544 | |
|
545 | 0 | cac_ops.select_file = cac_select_file; /* need to record object type */ |
546 | 0 | cac_ops.read_binary = cac_read_binary; |
547 | 0 | cac_ops.logout = cac_logout; |
548 | |
|
549 | 0 | return &cac1_drv; |
550 | 0 | } |
551 | | |
552 | | |
553 | | struct sc_card_driver * sc_get_cac1_driver(void) |
554 | 0 | { |
555 | 0 | return sc_get_driver(); |
556 | 0 | } |