/src/opensc/src/libopensc/card-dnie.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * card-dnie.c: Support for Spanish DNI electronico (DNIe card). |
3 | | * |
4 | | * Copyright (C) 2010 Juan Antonio Martinez <jonsito@terra.es> |
5 | | * |
6 | | * This work is derived from many sources at OpenSC Project site, |
7 | | * (see references) and the information made public for Spanish |
8 | | * Direccion General de la Policia y de la Guardia Civil |
9 | | * |
10 | | * This library is free software; you can redistribute it and/or |
11 | | * modify it under the terms of the GNU Lesser General Public |
12 | | * License as published by the Free Software Foundation; either |
13 | | * version 2.1 of the License, or (at your option) any later version. |
14 | | * |
15 | | * This library is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | | * Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; if not, write to the Free Software |
22 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 | | */ |
24 | | |
25 | | #define __CARD_DNIE_C__ |
26 | | |
27 | | #ifdef HAVE_CONFIG_H |
28 | | #include "config.h" |
29 | | #endif |
30 | | |
31 | | #if defined(ENABLE_OPENSSL) && defined(ENABLE_SM) /* empty file without openssl or sm */ |
32 | | |
33 | | #include <stdlib.h> |
34 | | #include <string.h> |
35 | | #include <stdarg.h> |
36 | | #include <sys/stat.h> |
37 | | |
38 | | #include "opensc.h" |
39 | | #include "cardctl.h" |
40 | | #include "internal.h" |
41 | | #include "cwa14890.h" |
42 | | #include "cwa-dnie.h" |
43 | | |
44 | | #ifdef _WIN32 |
45 | | |
46 | | #ifndef UNICODE |
47 | | #define UNICODE |
48 | | #endif |
49 | | |
50 | | #include <windows.h> |
51 | | #endif |
52 | | #ifdef __APPLE__ |
53 | | #include <Carbon/Carbon.h> |
54 | | #endif |
55 | | |
56 | 16.8k | #define MAX_RESP_BUFFER_SIZE 2048 |
57 | | |
58 | | /* default titles */ |
59 | | #define USER_CONSENT_TITLE "Confirm" |
60 | | |
61 | | extern int dnie_read_file( |
62 | | sc_card_t * card, |
63 | | const sc_path_t * path, |
64 | | sc_file_t ** file, |
65 | | u8 ** buffer, size_t * length); |
66 | | |
67 | | #define DNIE_CHIP_NAME "DNIe: Spanish eID card" |
68 | 3.09k | #define DNIE_CHIP_SHORTNAME "dnie" |
69 | 21.5k | #define DNIE_MF_NAME "Master.File" |
70 | | |
71 | | /* default user consent program (if required) */ |
72 | | #define USER_CONSENT_CMD "/usr/bin/pinentry" |
73 | | |
74 | | /** |
75 | | * SW internal apdu response table. |
76 | | * |
77 | | * Override APDU response error codes from iso7816.c to allow |
78 | | * handling of SM specific error |
79 | | */ |
80 | | static const struct sc_card_error dnie_errors[] = { |
81 | | {0x6688, SC_ERROR_SM, "Cryptographic checksum invalid"}, |
82 | | {0x6987, SC_ERROR_SM, "Expected SM Data Object missing"}, |
83 | | {0x6988, SC_ERROR_SM, "SM Data Object incorrect"}, |
84 | | {0, 0, NULL} |
85 | | }; |
86 | | |
87 | | /* |
88 | | * DNIe ATR info from DGP web page |
89 | | * |
90 | | Tag Value Meaning |
91 | | TS 0x3B Direct Convention |
92 | | T0 0x7F Y1=0x07=0111; TA1,TB1 y TC1 present. |
93 | | K=0x0F=1111; 15 historical bytes |
94 | | TA1 0x38 FI (Factor de conversión de la tasa de reloj) = 744 |
95 | | DI (Factor de ajuste de la tasa de bits) = 12 |
96 | | Máximo 8 Mhz. |
97 | | TB1 0x00 Vpp (voltaje de programación) no requerido. |
98 | | TC1 0x00 No se requiere tiempo de espera adicional. |
99 | | H1 0x00 No usado |
100 | | H2 0x6A Datos de preexpedición. Diez bytes con identificación del expedidor. |
101 | | H3 0x44 'D' |
102 | | H4 0x4E 'N' |
103 | | H5 0x49 'I' |
104 | | H6 0x65 'e' |
105 | | H7 Fabricante de la tecnología Match-on-Card incorporada. |
106 | | 0x10 SAGEM |
107 | | 0x20 SIEMENS |
108 | | H8 0x02 Fabricante del CI: STMicroelectronics. |
109 | | H9 0x4C |
110 | | H10 0x34 Tipo de CI: 19WL34 |
111 | | H11 0x01 MSB de la version del SO: 1 |
112 | | H12 0x1v LSB de la version del SO: 1v |
113 | | H13 Fase del ciclo de vida . |
114 | | 0x00 prepersonalización. |
115 | | 0x01 personalización. |
116 | | 0x03 usuario. |
117 | | 0x0F final. |
118 | | H14 0xss |
119 | | H15 0xss Bytes de estado |
120 | | |
121 | | H13-H15: 0x03 0x90 0x00 user phase: tarjeta operativa |
122 | | H13-H15: 0x0F 0x65 0x81 final phase: tarjeta no operativa |
123 | | */ |
124 | | |
125 | | /** |
126 | | * ATR Table list. |
127 | | * OpenDNIe defines two ATR's for user and finalized card state |
128 | | */ |
129 | | static struct sc_atr_table dnie_atrs[] = { |
130 | | /* TODO: get ATR for uninitialized DNIe */ |
131 | | { /** card activated; normal operation state */ |
132 | | "3B:7F:00:00:00:00:6A:44:4E:49:65:00:00:00:00:00:00:03:90:00", |
133 | | "FF:FF:00:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:FF:FF:FF", |
134 | | DNIE_CHIP_SHORTNAME, |
135 | | SC_CARD_TYPE_DNIE_USER, |
136 | | 0, |
137 | | NULL}, |
138 | | { /** card finalized, unusable */ |
139 | | "3B:7F:00:00:00:00:6A:44:4E:49:65:00:00:00:00:00:00:0F:65:81", |
140 | | "FF:FF:00:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:FF:FF:FF", |
141 | | DNIE_CHIP_SHORTNAME, |
142 | | SC_CARD_TYPE_DNIE_TERMINATED, |
143 | | 0, |
144 | | NULL}, |
145 | | {NULL, NULL, NULL, 0, 0, NULL} |
146 | | }; |
147 | | |
148 | | /** |
149 | | * Messages used on user consent procedures |
150 | | */ |
151 | | const char *user_consent_title="Signature Requested"; |
152 | | |
153 | | #ifdef linux |
154 | | const char *user_consent_message="Está a punto de realizar una firma electrónica con su clave de FIRMA del DNI electrónico. ¿Desea permitir esta operación?"; |
155 | | #else |
156 | | const char *user_consent_message="Esta a punto de realizar una firma digital\ncon su clave de FIRMA del DNI electronico.\nDesea permitir esta operacion?"; |
157 | | #endif |
158 | | |
159 | | #ifdef ENABLE_DNIE_UI |
160 | | /** |
161 | | * Messages used on pinentry protocol |
162 | | */ |
163 | | char *user_consent_msgs[] = { "SETTITLE", "SETDESC", "CONFIRM", "BYE" }; |
164 | | |
165 | | #if !defined(__APPLE__) && !defined(_WIN32) |
166 | | /** |
167 | | * Do fgets() without interruptions. |
168 | | * |
169 | | * Retry the operation if it is interrupted, such as with receiving an alarm. |
170 | | * |
171 | | * @param s Buffer receiving the data |
172 | | * @param size Size of the buffer |
173 | | * @param stream Stream to read |
174 | | * @return s on success, NULL on error |
175 | | */ |
176 | | static char *nointr_fgets(char *s, int size, FILE *stream) |
177 | | { |
178 | | while (fgets(s, size, stream) == NULL) { |
179 | | if (feof(stream) || errno != EINTR) |
180 | | return NULL; |
181 | | } |
182 | | return s; |
183 | | } |
184 | | #endif |
185 | | |
186 | | /** |
187 | | * Ask for user consent. |
188 | | * |
189 | | * Check for user consent configuration, |
190 | | * Invoke proper gui app and check result |
191 | | * |
192 | | * @param card pointer to sc_card structure |
193 | | * @param title Text to appear in the window header |
194 | | * @param text Message to show to the user |
195 | | * @return SC_SUCCESS on user consent OK , else error code |
196 | | */ |
197 | | int dnie_ask_user_consent(struct sc_card * card, const char *title, const char *message) |
198 | | { |
199 | | #ifdef __APPLE__ |
200 | | CFOptionFlags result; /* result code from the message box */ |
201 | | /* convert the strings from char* to CFStringRef */ |
202 | | CFStringRef header_ref; /* to store title */ |
203 | | CFStringRef message_ref; /* to store message */ |
204 | | #endif |
205 | | #if !defined(__APPLE__) && !defined(_WIN32) |
206 | | pid_t pid; |
207 | | FILE *fin=NULL; |
208 | | FILE *fout=NULL; /* to handle pipes as streams */ |
209 | | struct stat st_file; /* to verify that executable exists */ |
210 | | int srv_send[2]; /* to send data from server to client */ |
211 | | int srv_recv[2]; /* to receive data from client to server */ |
212 | | char outbuf[1024]; /* to compose and send messages */ |
213 | | char buf[1024]; /* to store client responses */ |
214 | | int n = 0; /* to iterate on to-be-sent messages */ |
215 | | #endif |
216 | | int res = SC_ERROR_INTERNAL; /* by default error :-( */ |
217 | | char *msg = NULL; /* to mark errors */ |
218 | | |
219 | | if ((card == NULL) || (card->ctx == NULL)) |
220 | | return SC_ERROR_INVALID_ARGUMENTS; |
221 | | LOG_FUNC_CALLED(card->ctx); |
222 | | |
223 | | if ((title==NULL) || (message==NULL)) |
224 | | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
225 | | |
226 | | if (GET_DNIE_UI_CTX(card).user_consent_enabled == 0 |
227 | | || card->ctx->flags & SC_CTX_FLAG_DISABLE_POPUPS) { |
228 | | sc_log(card->ctx, |
229 | | "User Consent or popups are disabled in configuration file"); |
230 | | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
231 | | } |
232 | | #ifdef _WIN32 |
233 | | /* in Windows, do not use pinentry, but MessageBox system call */ |
234 | | res = MessageBox ( |
235 | | NULL, |
236 | | TEXT(message), |
237 | | TEXT(title), |
238 | | MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_APPLMODAL |
239 | | ); |
240 | | if ( res == IDOK ) |
241 | | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
242 | | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED); |
243 | | #elif __APPLE__ |
244 | | /* Also in Mac OSX use native functions */ |
245 | | |
246 | | /* convert the strings from char* to CFStringRef */ |
247 | | header_ref = CFStringCreateWithCString( NULL, title, strlen(title) ); |
248 | | message_ref = CFStringCreateWithCString( NULL,message, strlen(message) ); |
249 | | |
250 | | /* Display user notification alert */ |
251 | | CFUserNotificationDisplayAlert( |
252 | | 0, /* no timeout */ |
253 | | kCFUserNotificationNoteAlertLevel, /* Alert level */ |
254 | | NULL, /* IconURL, use default, you can change */ |
255 | | /* it depending message_type flags */ |
256 | | NULL, /* SoundURL (not used) */ |
257 | | NULL, /* localization of strings */ |
258 | | header_ref, /* header. Cannot be null */ |
259 | | message_ref, /* message text */ |
260 | | CFSTR("Cancel"), /* default ( "OK" if null) button text */ |
261 | | CFSTR("OK"), /* second button title */ |
262 | | NULL, /* third button title, null--> no other button */ |
263 | | &result /* response flags */ |
264 | | ); |
265 | | |
266 | | /* Clean up the strings */ |
267 | | CFRelease( header_ref ); |
268 | | CFRelease( message_ref ); |
269 | | /* Return 0 only if "OK" is selected */ |
270 | | if( result == kCFUserNotificationAlternateResponse ) |
271 | | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
272 | | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED); |
273 | | #else |
274 | | /* just a simple bidirectional pipe+fork+exec implementation */ |
275 | | /* In a pipe, xx[0] is for reading, xx[1] is for writing */ |
276 | | if (pipe(srv_send) < 0) { |
277 | | msg = "pipe(srv_send)"; |
278 | | goto do_error; |
279 | | } |
280 | | if (pipe(srv_recv) < 0) { |
281 | | msg = "pipe(srv_recv)"; |
282 | | goto do_error; |
283 | | } |
284 | | pid = fork(); |
285 | | switch (pid) { |
286 | | case -1: /* error */ |
287 | | msg = "fork()"; |
288 | | goto do_error; |
289 | | case 0: /* child */ |
290 | | /* make our pipes, our new stdin & stderr, closing older ones */ |
291 | | dup2(srv_send[0], STDIN_FILENO); /* map srv send for input */ |
292 | | dup2(srv_recv[1], STDOUT_FILENO); /* map srv_recv for output */ |
293 | | /* once dup2'd pipes are no longer needed on client; so close */ |
294 | | close(srv_send[0]); |
295 | | close(srv_send[1]); |
296 | | close(srv_recv[0]); |
297 | | close(srv_recv[1]); |
298 | | /* check that user_consent_app exists. TODO: check if executable */ |
299 | | res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file); |
300 | | if (res != 0) { |
301 | | sc_log(card->ctx, "Invalid pinentry application: %s\n", |
302 | | GET_DNIE_UI_CTX(card).user_consent_app); |
303 | | } else { |
304 | | /* call exec() with proper user_consent_app from configuration */ |
305 | | /* if ok should never return */ |
306 | | execlp(GET_DNIE_UI_CTX(card).user_consent_app, GET_DNIE_UI_CTX(card).user_consent_app, (char *)NULL); |
307 | | sc_log(card->ctx, "execlp() error"); |
308 | | } |
309 | | abort(); |
310 | | default: /* parent */ |
311 | | /* Close the pipe ends that the child uses to read from / write to |
312 | | * so when we close the others, an EOF will be transmitted properly. |
313 | | */ |
314 | | close(srv_send[0]); |
315 | | close(srv_recv[1]); |
316 | | /* use iostreams to take care on newlines and text based data */ |
317 | | fin = fdopen(srv_recv[0], "r"); |
318 | | if (fin == NULL) { |
319 | | msg = "fdopen(in)"; |
320 | | goto do_error; |
321 | | } |
322 | | fout = fdopen(srv_send[1], "w"); |
323 | | if (fout == NULL) { |
324 | | msg = "fdopen(out)"; |
325 | | goto do_error; |
326 | | } |
327 | | /* read and ignore first line */ |
328 | | if (nointr_fgets(buf, sizeof(buf), fin) == NULL) { |
329 | | res = SC_ERROR_INTERNAL; |
330 | | msg = "nointr_fgets() Unexpected IOError/EOF"; |
331 | | goto do_error; |
332 | | } |
333 | | for (n = 0; n<4; n++) { |
334 | | char *pt; |
335 | | if (n==0) snprintf(outbuf, sizeof outbuf,"%s %s\n",user_consent_msgs[0],title); |
336 | | else if (n==1) snprintf(outbuf, sizeof outbuf,"%s %s\n",user_consent_msgs[1],message); |
337 | | else snprintf(outbuf, sizeof outbuf,"%s\n",user_consent_msgs[n]); |
338 | | /* send message */ |
339 | | fputs(outbuf, fout); |
340 | | fflush(fout); |
341 | | /* get response */ |
342 | | pt=nointr_fgets(buf, sizeof(buf), fin); |
343 | | if (pt==NULL) { |
344 | | res = SC_ERROR_INTERNAL; |
345 | | msg = "nointr_fgets() Unexpected IOError/EOF"; |
346 | | goto do_error; |
347 | | } |
348 | | if (strstr(buf, "OK") == NULL) { |
349 | | res = SC_ERROR_NOT_ALLOWED; |
350 | | msg = "fail/cancel"; |
351 | | goto do_error; |
352 | | } |
353 | | } |
354 | | } /* switch */ |
355 | | /* arriving here means signature has been accepted by user */ |
356 | | res = SC_SUCCESS; |
357 | | msg = NULL; |
358 | | do_error: |
359 | | /* close out channel to force client receive EOF and also die */ |
360 | | if (fout != NULL) fclose(fout); |
361 | | if (fin != NULL) fclose(fin); |
362 | | #endif |
363 | | if (msg != NULL) |
364 | | sc_log(card->ctx, "%s", msg); |
365 | | LOG_FUNC_RETURN(card->ctx, res); |
366 | | } |
367 | | |
368 | | #endif /* ENABLE_DNIE_UI */ |
369 | | |
370 | | /** |
371 | | * DNIe specific card driver operations |
372 | | */ |
373 | | static struct sc_card_operations dnie_ops; |
374 | | |
375 | | /** |
376 | | * Local copy of iso7816 card driver operations |
377 | | */ |
378 | | static struct sc_card_operations *iso_ops = NULL; |
379 | | |
380 | | /** |
381 | | * Module definition for OpenDNIe card driver |
382 | | */ |
383 | | static sc_card_driver_t dnie_driver = { |
384 | | DNIE_CHIP_NAME, /**< Full name for DNIe card driver */ |
385 | | DNIE_CHIP_SHORTNAME, /**< Short name for DNIe card driver */ |
386 | | &dnie_ops, /**< pointer to dnie_ops (DNIe card driver operations) */ |
387 | | dnie_atrs, /**< List of card ATR's handled by this driver */ |
388 | | 0, /**< (natrs) number of atr's to check for this driver */ |
389 | | NULL /**< (dll) Card driver module (on DNIe is null) */ |
390 | | }; |
391 | | |
392 | | /************************** card-dnie.c internal functions ****************/ |
393 | | |
394 | | /** |
395 | | * Parse configuration file for dnie parameters. |
396 | | * |
397 | | * DNIe card driver has two main parameters: |
398 | | * - The name of the user consent Application to be used in Linux. This application should be any of pinentry-xxx family |
399 | | * - A flag to indicate if user consent is to be used in this driver. If false, the user won't be prompted for confirmation on signature operations |
400 | | * |
401 | | * @See ../../etc/opensc.conf for details |
402 | | * @param card Pointer to card structure |
403 | | * @param ui_context Pointer to ui_context structure to store data into |
404 | | * @return SC_SUCCESS (should return no errors) |
405 | | * |
406 | | * TODO: Code should be revised in order to store user consent info |
407 | | * in a card-independent way at configuration file |
408 | | */ |
409 | | #ifdef ENABLE_DNIE_UI |
410 | | static int dnie_get_environment( |
411 | | sc_card_t * card, |
412 | | ui_context_t * ui_context) |
413 | | { |
414 | | int i; |
415 | | scconf_block **blocks, *blk; |
416 | | sc_context_t *ctx; |
417 | | /* set default values */ |
418 | | ui_context->user_consent_app = USER_CONSENT_CMD; |
419 | | ui_context->user_consent_enabled = 1; |
420 | | /* look for sc block in opensc.conf */ |
421 | | ctx = card->ctx; |
422 | | for (i = 0; ctx->conf_blocks[i]; i++) { |
423 | | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], |
424 | | "card_driver", "dnie"); |
425 | | if (!blocks) |
426 | | continue; |
427 | | blk = blocks[0]; |
428 | | free(blocks); |
429 | | if (blk == NULL) |
430 | | continue; |
431 | | /* fill private data with configuration parameters */ |
432 | | ui_context->user_consent_app = /* def user consent app is "pinentry" */ |
433 | | (char *)scconf_get_str(blk, "user_consent_app", |
434 | | USER_CONSENT_CMD); |
435 | | ui_context->user_consent_enabled = /* user consent is enabled by default */ |
436 | | scconf_get_bool(blk, "user_consent_enabled", 1); |
437 | | } |
438 | | return SC_SUCCESS; |
439 | | } |
440 | | #endif |
441 | | |
442 | | /************************** cardctl defined operations *******************/ |
443 | | |
444 | | /** |
445 | | * Generate a public/private key pair. |
446 | | * |
447 | | * Manual says that generate_keys() is a reserved operation; that is: |
448 | | * only can be done at DGP offices. But several authors talk about |
449 | | * this operation is available also outside. So need to test :-) |
450 | | * Notice that write operations are not supported, so we can't use |
451 | | * created keys to generate and store new certificates into the card. |
452 | | * TODO: copy code from card-jcop.c::jcop_generate_keys() |
453 | | * @param card pointer to card info data |
454 | | * @param data where to store function results |
455 | | * @return SC_SUCCESS if ok, else error code |
456 | | */ |
457 | | static int dnie_generate_key(sc_card_t * card, void *data) |
458 | 0 | { |
459 | 0 | int result = SC_ERROR_NOT_SUPPORTED; |
460 | 0 | if ((card == NULL) || (data == NULL)) |
461 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
462 | 0 | LOG_FUNC_CALLED(card->ctx); |
463 | | /* TODO: write dnie_generate_key() */ |
464 | 0 | LOG_FUNC_RETURN(card->ctx, result); |
465 | 0 | } |
466 | | |
467 | | /** |
468 | | * Analyze a buffer looking for provided data pattern. |
469 | | * |
470 | | * Commodity function for dnie_get_info() that searches a byte array |
471 | | * in provided buffer |
472 | | * |
473 | | * @param card pointer to card info data |
474 | | * @param pat data pattern to find in buffer |
475 | | * @param buf where to look for pattern |
476 | | * @param len buffer length |
477 | | * @return retrieved value or NULL if pattern not found |
478 | | * @see dnie_get_info() |
479 | | */ |
480 | | static char *findPattern(u8 *pat, u8 *buf, size_t len) |
481 | 0 | { |
482 | 0 | char *res = NULL; |
483 | 0 | u8 *from = buf; |
484 | 0 | int size = 0; |
485 | | /* Locate pattern. Assume pattern length=6 */ |
486 | 0 | for ( from = buf; from < buf+len-6; from++) { |
487 | 0 | if (memcmp(from,pat,6) == 0 ) goto data_found; |
488 | 0 | } |
489 | | /* arriving here means pattern not found */ |
490 | 0 | return NULL; |
491 | | |
492 | 0 | data_found: |
493 | | /* assume length is less than 128 bytes, so is coded in 1 byte */ |
494 | 0 | size = 0x000000ff & (int) *(from+6); |
495 | 0 | if ( size == 0 ) return NULL; /* empty data */ |
496 | 0 | res = calloc( size+1, sizeof(char) ); |
497 | 0 | if ( res == NULL) return NULL; /* calloc() error */ |
498 | 0 | memcpy(res,from+7,size); |
499 | 0 | return res; |
500 | 0 | } |
501 | | |
502 | | /** |
503 | | * Retrieve name, surname, and DNIe number. |
504 | | * |
505 | | * This is done by mean of reading and parsing CDF file |
506 | | * at address 3F0050156004 |
507 | | * No need to enter pin nor use Secure Channel |
508 | | * |
509 | | * Notice that this is done by mean of a dirty trick: instead |
510 | | * of parsing ASN1 data on EF(CDF), |
511 | | * we look for desired OID patterns in binary array |
512 | | * |
513 | | * @param card pointer to card info data |
514 | | * @param data where to store function results (number,name,surname,idesp,version) |
515 | | * @return SC_SUCCESS if ok, else error code |
516 | | */ |
517 | | static int dnie_get_info(sc_card_t * card, char *data[]) |
518 | 0 | { |
519 | 0 | sc_file_t *file = NULL; |
520 | 0 | sc_path_t path; |
521 | 0 | u8 *buffer = NULL; |
522 | 0 | size_t bufferlen = 0; |
523 | 0 | char *msg = NULL; |
524 | 0 | u8 SerialNumber [] = { 0x06, 0x03, 0x55, 0x04, 0x05, 0x13 }; |
525 | 0 | u8 Name [] = { 0x06, 0x03, 0x55, 0x04, 0x04, 0x0C }; |
526 | 0 | u8 GivenName [] = { 0x06, 0x03, 0x55, 0x04, 0x2A, 0x0C }; |
527 | 0 | int res = SC_ERROR_NOT_SUPPORTED; |
528 | |
|
529 | 0 | if ((card == NULL) || (data == NULL)) |
530 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
531 | 0 | LOG_FUNC_CALLED(card->ctx); |
532 | | |
533 | | /* phase 1: get DNIe number, Name and GivenName */ |
534 | | |
535 | | /* read EF(CDF) at 3F0050156004 */ |
536 | 0 | sc_format_path("3F0050156004", &path); |
537 | 0 | res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); |
538 | 0 | if (res != SC_SUCCESS) { |
539 | 0 | msg = "Cannot read EF(CDF)"; |
540 | 0 | goto get_info_end; |
541 | 0 | } |
542 | | /* locate OID 2.5.4.5 (SerialNumber) - DNIe number*/ |
543 | 0 | data[0]= findPattern(SerialNumber,buffer,bufferlen); |
544 | | /* locate OID 2.5.4.4 (Name) - Apellidos */ |
545 | 0 | data[1]= findPattern(Name,buffer,bufferlen); |
546 | | /* locate OID 2.5.4.42 (GivenName) - Nombre */ |
547 | 0 | data[2]= findPattern(GivenName,buffer,bufferlen); |
548 | 0 | if ( ! data[0] || !data[1] || !data[2] ) { |
549 | 0 | res = SC_ERROR_INVALID_DATA; |
550 | 0 | msg = "Cannot retrieve info from EF(CDF)"; |
551 | 0 | goto get_info_end; |
552 | 0 | } |
553 | | |
554 | | /* phase 2: get IDESP */ |
555 | 0 | sc_format_path("3F000006", &path); |
556 | 0 | sc_file_free(file); |
557 | 0 | file = NULL; |
558 | 0 | if (buffer) { |
559 | 0 | free(buffer); |
560 | 0 | buffer=NULL; |
561 | 0 | bufferlen=0; |
562 | 0 | } |
563 | 0 | res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); |
564 | 0 | if (res != SC_SUCCESS) { |
565 | 0 | data[3]=NULL; |
566 | 0 | goto get_info_ph3; |
567 | 0 | } |
568 | 0 | data[3]=calloc(bufferlen+1,sizeof(char)); |
569 | 0 | if ( !data[3] ) { |
570 | 0 | msg = "Cannot allocate memory for IDESP data"; |
571 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
572 | 0 | goto get_info_end; |
573 | 0 | } |
574 | 0 | memcpy(data[3],buffer,bufferlen); |
575 | |
|
576 | 0 | get_info_ph3: |
577 | | /* phase 3: get DNIe software version */ |
578 | 0 | sc_format_path("3F002F03", &path); |
579 | 0 | sc_file_free(file); |
580 | 0 | file = NULL; |
581 | 0 | if (buffer) { |
582 | 0 | free(buffer); |
583 | 0 | buffer=NULL; |
584 | 0 | bufferlen=0; |
585 | 0 | } |
586 | | /* |
587 | | * Some old DNIe cards seems not to include SW version file, |
588 | | * so let this code fail without notice |
589 | | */ |
590 | 0 | res = dnie_read_file(card, &path, &file, &buffer, &bufferlen); |
591 | 0 | if (res != SC_SUCCESS) { |
592 | 0 | msg = "Cannot read DNIe Version EF"; |
593 | 0 | data[4]=NULL; |
594 | 0 | res = SC_SUCCESS; /* let function return successfully */ |
595 | 0 | goto get_info_end; |
596 | 0 | } |
597 | 0 | data[4]=calloc(bufferlen+1,sizeof(char)); |
598 | 0 | if ( !data[4] ) { |
599 | 0 | msg = "Cannot allocate memory for DNIe Version data"; |
600 | 0 | res = SC_ERROR_OUT_OF_MEMORY; |
601 | 0 | goto get_info_end; |
602 | 0 | } |
603 | 0 | memcpy(data[4],buffer,bufferlen); |
604 | | |
605 | | /* arriving here means ok */ |
606 | 0 | res = SC_SUCCESS; |
607 | 0 | msg = NULL; |
608 | |
|
609 | 0 | get_info_end: |
610 | 0 | sc_file_free(file); |
611 | 0 | file = NULL; |
612 | 0 | if (buffer) { |
613 | 0 | free(buffer); |
614 | 0 | buffer=NULL; |
615 | 0 | bufferlen=0; |
616 | 0 | } |
617 | 0 | if (msg) |
618 | 0 | sc_log(card->ctx, "%s", msg); |
619 | 0 | LOG_FUNC_RETURN(card->ctx, res); |
620 | 0 | } |
621 | | |
622 | | /** |
623 | | * Retrieve serial number (7 bytes) from card. |
624 | | * |
625 | | * This is done by mean of an special APDU command described |
626 | | * in the DNIe Reference Manual |
627 | | * |
628 | | * @param card pointer to card description |
629 | | * @param serial where to store data retrieved |
630 | | * @return SC_SUCCESS if ok; else error code |
631 | | */ |
632 | | static int dnie_get_serialnr(sc_card_t * card, sc_serial_number_t * serial) |
633 | 133 | { |
634 | 133 | int result; |
635 | 133 | sc_apdu_t apdu; |
636 | 133 | u8 rbuf[MAX_RESP_BUFFER_SIZE]; |
637 | 133 | if ((card == NULL) || (card->ctx == NULL) || (serial == NULL)) |
638 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
639 | | |
640 | 133 | LOG_FUNC_CALLED(card->ctx); |
641 | 133 | if (card->type != SC_CARD_TYPE_DNIE_USER) |
642 | 0 | return SC_ERROR_NOT_SUPPORTED; |
643 | | /* if serial number is cached, use it */ |
644 | 133 | if (card->serialnr.len) { |
645 | 6 | memcpy(serial, &card->serialnr, sizeof(*serial)); |
646 | 6 | sc_log_hex(card->ctx, "Serial Number (cached)", serial->value, serial->len); |
647 | 6 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
648 | 6 | } |
649 | | /* not cached, retrieve it by mean of an APDU */ |
650 | | /* official driver read 0x11 bytes, but only uses 7. Manual says just 7 (for le) */ |
651 | 127 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xb8, 0x00, 0x00, 0x07, 0, |
652 | 127 | rbuf, sizeof(rbuf), NULL, 0); |
653 | 127 | apdu.cla = 0x90; /* proprietary cmd */ |
654 | | /* send apdu */ |
655 | 127 | result = sc_transmit_apdu(card, &apdu); |
656 | 127 | if (result != SC_SUCCESS) { |
657 | 13 | LOG_TEST_RET(card->ctx, result, "APDU transmit failed"); |
658 | 13 | } |
659 | 114 | if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) |
660 | 93 | return SC_ERROR_INTERNAL; |
661 | | /* cache serial number */ |
662 | 21 | memcpy(card->serialnr.value, apdu.resp, 7 * sizeof(u8)); |
663 | 21 | card->serialnr.len = 7 * sizeof(u8); |
664 | | /* TODO: fill Issuer Identification Number data with proper (ATR?) info */ |
665 | | /* |
666 | | card->serialnr.iin.mii=; |
667 | | card->serialnr.iin.country=; |
668 | | card->serialnr.iin.issuer_id=; |
669 | | */ |
670 | | /* copy and return serial number */ |
671 | 21 | memcpy(serial, &card->serialnr, sizeof(*serial)); |
672 | 21 | sc_log_hex(card->ctx, "Serial Number (apdu)", serial->value, serial->len); |
673 | 21 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
674 | 21 | } |
675 | | |
676 | | /** |
677 | | * Remove the binary data in the cache. |
678 | | * |
679 | | * It frees memory if allocated and resets pointer and length. |
680 | | * It only touches the private binary cache variables, not the sc_card information. |
681 | | * |
682 | | * @param data pointer to dnie private data |
683 | | */ |
684 | | static void dnie_clear_cache(dnie_private_data_t * data) |
685 | 18.1k | { |
686 | 18.1k | if (data == NULL) return; |
687 | 18.1k | if (data->cache != NULL) |
688 | 1.58k | free(data->cache); |
689 | 18.1k | data->cache = NULL; |
690 | 18.1k | data->cachelen = 0; |
691 | 18.1k | } |
692 | | |
693 | | /** |
694 | | * Set sc_card flags according to DNIe requirements. |
695 | | * |
696 | | * Used in card initialization. |
697 | | * |
698 | | * @param card pointer to card data |
699 | | */ |
700 | | static void init_flags(struct sc_card *card) |
701 | 3.09k | { |
702 | 3.09k | unsigned long algoflags; |
703 | | /* set up flags according documentation */ |
704 | 3.09k | card->name = DNIE_CHIP_SHORTNAME; |
705 | 3.09k | card->cla = 0x00; /* default APDU class (interindustry) */ |
706 | 3.09k | card->caps |= SC_CARD_CAP_RNG; /* we have a random number generator */ |
707 | 3.09k | card->max_send_size = (255 - 12); /* manual says 255, but we need 12 extra bytes when encoding */ |
708 | 3.09k | card->max_recv_size = 255; |
709 | | |
710 | | /* RSA Support with PKCS1.5 padding */ |
711 | 3.09k | algoflags = SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1; |
712 | 3.09k | _sc_card_add_rsa_alg(card, 1024, algoflags, 0); |
713 | 3.09k | _sc_card_add_rsa_alg(card, 1920, algoflags, 0); |
714 | 3.09k | _sc_card_add_rsa_alg(card, 2048, algoflags, 0); |
715 | 3.09k | } |
716 | | |
717 | | /**************************** sc_card_operations **********************/ |
718 | | |
719 | | /* Generic operations */ |
720 | | |
721 | | /** |
722 | | * Check if provided card can be handled by OpenDNIe. |
723 | | * |
724 | | * Called in sc_connect_card(). Must return 1, if the current |
725 | | * card can be handled with this driver, or 0 otherwise. ATR |
726 | | * field of the sc_card struct is filled in before calling |
727 | | * this function. |
728 | | * do not declare static, as used by pkcs15-dnie module |
729 | | * |
730 | | * @param card Pointer to card structure |
731 | | * @return on card matching 0 if not match; negative return means error |
732 | | */ |
733 | | int dnie_match_card(struct sc_card *card) |
734 | 113k | { |
735 | 113k | int result = 0; |
736 | 113k | int matched = -1; |
737 | 113k | LOG_FUNC_CALLED(card->ctx); |
738 | 113k | matched = _sc_match_atr(card, dnie_atrs, &card->type); |
739 | 113k | result = (matched >= 0) ? 1 : 0; |
740 | 113k | LOG_FUNC_RETURN(card->ctx, result); |
741 | 113k | } |
742 | | |
743 | | static int dnie_sm_free_wrapped_apdu(struct sc_card *card, |
744 | | struct sc_apdu *plain, struct sc_apdu **sm_apdu) |
745 | 0 | { |
746 | 0 | struct sc_context *ctx = card->ctx; |
747 | 0 | cwa_provider_t *provider = NULL; |
748 | 0 | int rv = SC_SUCCESS; |
749 | |
|
750 | 0 | LOG_FUNC_CALLED(ctx); |
751 | 0 | provider = GET_DNIE_PRIV_DATA(card)->cwa_provider; |
752 | 0 | if (!sm_apdu) |
753 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
754 | 0 | if (!(*sm_apdu)) |
755 | 0 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
756 | | |
757 | 0 | if ((*sm_apdu) != plain) { |
758 | 0 | rv = cwa_decode_response(card, provider, *sm_apdu); |
759 | 0 | if (plain && rv == SC_SUCCESS) { |
760 | 0 | if (plain->resp) { |
761 | | /* copy the response into the original resp buffer */ |
762 | 0 | if ((*sm_apdu)->resplen <= plain->resplen) { |
763 | 0 | memcpy(plain->resp, (*sm_apdu)->resp, (*sm_apdu)->resplen); |
764 | 0 | plain->resplen = (*sm_apdu)->resplen; |
765 | 0 | } else { |
766 | 0 | sc_log(card->ctx, "Invalid initial length," |
767 | 0 | " needed %"SC_FORMAT_LEN_SIZE_T"u bytes" |
768 | 0 | " but has %"SC_FORMAT_LEN_SIZE_T"u", |
769 | 0 | (*sm_apdu)->resplen, plain->resplen); |
770 | 0 | rv = SC_ERROR_BUFFER_TOO_SMALL; |
771 | 0 | } |
772 | 0 | } |
773 | 0 | plain->sw1 = (*sm_apdu)->sw1; |
774 | 0 | plain->sw2 = (*sm_apdu)->sw2; |
775 | 0 | } |
776 | 0 | if (plain == NULL || (*sm_apdu)->data != plain->data) |
777 | 0 | free((unsigned char *) (*sm_apdu)->data); |
778 | 0 | if (plain == NULL || (*sm_apdu)->resp != plain->resp) |
779 | 0 | free((*sm_apdu)->resp); |
780 | 0 | free(*sm_apdu); |
781 | 0 | } |
782 | 0 | *sm_apdu = NULL; |
783 | |
|
784 | 0 | LOG_FUNC_RETURN(ctx, rv); |
785 | 0 | } |
786 | | |
787 | | static int dnie_sm_get_wrapped_apdu(struct sc_card *card, |
788 | | struct sc_apdu *plain, struct sc_apdu **sm_apdu) |
789 | 0 | { |
790 | 0 | struct sc_context *ctx = card->ctx; |
791 | 0 | cwa_provider_t *provider = NULL; |
792 | 0 | int rv = SC_SUCCESS; |
793 | |
|
794 | 0 | LOG_FUNC_CALLED(ctx); |
795 | 0 | if (!plain || !sm_apdu) |
796 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
797 | | |
798 | 0 | provider = GET_DNIE_PRIV_DATA(card)->cwa_provider; |
799 | |
|
800 | 0 | if (((plain->cla & 0x0C) == 0) && (plain->ins != 0xC0)) { |
801 | 0 | *sm_apdu = calloc(1, sizeof(struct sc_apdu)); |
802 | 0 | if (!(*sm_apdu)) |
803 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
804 | | |
805 | 0 | rv = cwa_encode_apdu(card, provider, plain, *sm_apdu); |
806 | |
|
807 | 0 | if (rv != SC_SUCCESS) { |
808 | 0 | dnie_sm_free_wrapped_apdu(card, plain, sm_apdu); |
809 | 0 | } |
810 | 0 | } else |
811 | 0 | *sm_apdu = plain; |
812 | | |
813 | 0 | LOG_FUNC_RETURN(ctx, rv); |
814 | 0 | } |
815 | | |
816 | | /** |
817 | | * OpenDNIe card structures initialization. |
818 | | * |
819 | | * Called when ATR of the inserted card matches an entry in ATR |
820 | | * table. May return SC_ERROR_INVALID_CARD to indicate that |
821 | | * the card cannot be handled with this driver. |
822 | | * |
823 | | * @param card Pointer to card structure |
824 | | * @return SC_SUCCES if ok; else error code |
825 | | */ |
826 | | static int dnie_init(struct sc_card *card) |
827 | 3.12k | { |
828 | 3.12k | int res = SC_SUCCESS; |
829 | 3.12k | sc_context_t *ctx = card->ctx; |
830 | 3.12k | cwa_provider_t *provider = NULL; |
831 | | |
832 | 3.12k | LOG_FUNC_CALLED(ctx); |
833 | | |
834 | | /* if recognized as terminated DNIe card, return error */ |
835 | 3.12k | if (card->type == SC_CARD_TYPE_DNIE_TERMINATED) |
836 | 3.12k | LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "DNIe card is terminated."); |
837 | | |
838 | | /* create and initialize cwa-dnie provider*/ |
839 | 3.09k | provider = dnie_get_cwa_provider(card); |
840 | 3.09k | if (!provider) |
841 | 3.09k | LOG_TEST_RET(card->ctx, SC_ERROR_INTERNAL, "Error initializing cwa-dnie provider"); |
842 | | |
843 | | /** Secure messaging initialization section **/ |
844 | 3.09k | memset(&(card->sm_ctx), 0, sizeof(sm_context_t)); |
845 | 3.09k | card->sm_ctx.ops.get_sm_apdu = dnie_sm_get_wrapped_apdu; |
846 | 3.09k | card->sm_ctx.ops.free_sm_apdu = dnie_sm_free_wrapped_apdu; |
847 | 3.09k | card->sm_ctx.sm_mode = SM_MODE_NONE; |
848 | | |
849 | 3.09k | res=cwa_create_secure_channel(card,provider,CWA_SM_OFF); |
850 | 3.09k | LOG_TEST_RET(card->ctx, res, "Failure creating CWA secure channel."); |
851 | | |
852 | | /* initialize private data */ |
853 | 3.09k | card->drv_data = calloc(1, sizeof(dnie_private_data_t)); |
854 | 3.09k | if (card->drv_data == NULL) |
855 | 3.09k | LOG_TEST_RET(card->ctx, SC_ERROR_OUT_OF_MEMORY, "Could not allocate DNIe private data."); |
856 | | |
857 | | #ifdef ENABLE_DNIE_UI |
858 | | /* read environment from configuration file */ |
859 | | res = dnie_get_environment(card, &(GET_DNIE_UI_CTX(card))); |
860 | | if (res != SC_SUCCESS) { |
861 | | free(card->drv_data); |
862 | | LOG_TEST_RET(card->ctx, res, "Failure reading DNIe environment."); |
863 | | } |
864 | | #endif |
865 | | |
866 | 3.09k | init_flags(card); |
867 | | |
868 | 3.09k | GET_DNIE_PRIV_DATA(card)->cwa_provider = provider; |
869 | | |
870 | 3.09k | LOG_FUNC_RETURN(card->ctx, res); |
871 | 3.09k | } |
872 | | |
873 | | /** |
874 | | * De-initialization routine. |
875 | | * |
876 | | * Called when the card object is being freed. finish() has to |
877 | | * deallocate all possible private data. |
878 | | * |
879 | | * @param card Pointer to card driver data structure |
880 | | * @return SC_SUCCESS if ok; else error code |
881 | | */ |
882 | | static int dnie_finish(struct sc_card *card) |
883 | 3.09k | { |
884 | 3.09k | int result = SC_SUCCESS; |
885 | 3.09k | LOG_FUNC_CALLED(card->ctx); |
886 | 3.09k | dnie_clear_cache(GET_DNIE_PRIV_DATA(card)); |
887 | | /* disable sm channel if established */ |
888 | 3.09k | result = cwa_create_secure_channel(card, GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_OFF); |
889 | 3.09k | free(GET_DNIE_PRIV_DATA(card)->cwa_provider); |
890 | 3.09k | free(card->drv_data); |
891 | 3.09k | LOG_FUNC_RETURN(card->ctx, result); |
892 | 3.09k | } |
893 | | |
894 | | /* ISO 7816-4 functions */ |
895 | | |
896 | | /** |
897 | | * Check whether data are compressed. |
898 | | * |
899 | | * @param card pointer to sc_card_t structure |
900 | | * @param from buffer to get data from |
901 | | * @param len buffer length |
902 | | * @return 1 if data are compressed, 0 otherwise; len points to expected length of decompressed data |
903 | | */ |
904 | | |
905 | | static int dnie_is_compressed(sc_card_t * card, u8 * from, size_t len) |
906 | 1.62k | { |
907 | 1.62k | #ifdef ENABLE_ZLIB |
908 | 1.62k | size_t uncompressed = 0L; |
909 | 1.62k | size_t compressed = 0L; |
910 | | |
911 | 1.62k | if (!card || !card->ctx || !from || !len) |
912 | 35 | return 0; |
913 | 1.58k | LOG_FUNC_CALLED(card->ctx); |
914 | | |
915 | | /* if data size not enough for compression header assume uncompressed */ |
916 | 1.58k | if (len < 8) |
917 | 126 | goto compress_exit; |
918 | | /* evaluate compressed an uncompressed sizes (little endian format) */ |
919 | 1.46k | uncompressed = lebytes2ulong(from); |
920 | 1.46k | compressed = lebytes2ulong(from + 4); |
921 | | /* if compressed size doesn't match data length assume not compressed */ |
922 | 1.46k | if (compressed != len - 8) |
923 | 1.18k | goto compress_exit; |
924 | | /* if compressed size greater than uncompressed, assume uncompressed data */ |
925 | 278 | if (uncompressed < compressed) |
926 | 5 | goto compress_exit; |
927 | | /* Do not try to allocate insane size if we receive bogus data */ |
928 | 273 | if (uncompressed > MAX_FILE_SIZE) |
929 | 144 | goto compress_exit; |
930 | | |
931 | 129 | sc_log(card->ctx, "Data seems to be compressed."); |
932 | 129 | return 1; |
933 | 1.45k | compress_exit: |
934 | 1.45k | #endif |
935 | | |
936 | 1.45k | sc_log(card->ctx, "Data not compressed."); |
937 | 1.45k | return 0; |
938 | 273 | } |
939 | | |
940 | | /** |
941 | | * Fill file cache for read_binary() operation. |
942 | | * |
943 | | * Fill a temporary buffer by mean of consecutive calls to read_binary() |
944 | | * until card sends eof |
945 | | * |
946 | | * DNIe card stores user certificates in compressed format. so we need |
947 | | * some way to detect and uncompress on-the-fly compressed files, to |
948 | | * let read_binary() work transparently. |
949 | | * This is the main goal of this routine: create an in-memory buffer |
950 | | * for read_binary operation, filling this buffer on first read_binary() |
951 | | * call, and uncompress data if compression detected. Further |
952 | | * read_binary() calls then make use of cached data, instead |
953 | | * of accessing the card |
954 | | * |
955 | | * @param card Pointer to card structure |
956 | | * @return SC_SUCCESS if OK; else error code |
957 | | */ |
958 | | static int dnie_fill_cache(sc_card_t * card,unsigned long *flags) |
959 | 7.75k | { |
960 | 7.75k | u8 tmp[MAX_RESP_BUFFER_SIZE]; |
961 | 7.75k | sc_apdu_t apdu; |
962 | 7.75k | size_t count = 0; |
963 | 7.75k | size_t len = 0; |
964 | 7.75k | u8 *buffer = NULL; |
965 | 7.75k | u8 *p; |
966 | 7.75k | sc_context_t *ctx = NULL; |
967 | | |
968 | 7.75k | if (!card || !card->ctx) |
969 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
970 | 7.75k | ctx = card->ctx; |
971 | | |
972 | 7.75k | LOG_FUNC_CALLED(ctx); |
973 | | |
974 | | /* mark cache empty */ |
975 | 7.75k | dnie_clear_cache(GET_DNIE_PRIV_DATA(card)); |
976 | | |
977 | | /* initialize apdu */ |
978 | 7.75k | sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, 0x00, 0x00); |
979 | | |
980 | | /* try to read_binary while data available but never long than 32767 */ |
981 | 7.75k | count = card->max_recv_size; |
982 | 15.9k | for (len = 0; len < 0x7fff;) { |
983 | 15.9k | int r = SC_SUCCESS; |
984 | | /* fill apdu */ |
985 | 15.9k | apdu.p1 = 0xff & (len >> 8); |
986 | 15.9k | apdu.p2 = 0xff & len; |
987 | 15.9k | apdu.le = count; |
988 | 15.9k | apdu.resplen = MAX_RESP_BUFFER_SIZE; |
989 | 15.9k | apdu.resp = tmp; |
990 | | /* transmit apdu */ |
991 | 15.9k | r = sc_transmit_apdu(card, &apdu); |
992 | 15.9k | if (r != SC_SUCCESS) { |
993 | 4.25k | free(buffer); |
994 | 4.25k | if (apdu.resp != tmp) |
995 | 0 | free(apdu.resp); |
996 | 4.25k | sc_log(ctx, "read_binary() APDU transmit failed"); |
997 | 4.25k | LOG_FUNC_RETURN(ctx, r); |
998 | 4.25k | } |
999 | 11.6k | if (apdu.resplen == 0) { |
1000 | | /* on no data received, check if requested len is longer than |
1001 | | available data in card. If so, ask just for remaining data */ |
1002 | 4.62k | r = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1003 | 4.62k | if (r == SC_ERROR_WRONG_LENGTH) { |
1004 | 2.72k | count = 0xff & apdu.sw2; |
1005 | 2.72k | if (count != 0) { |
1006 | 2.70k | if (apdu.resp != tmp) |
1007 | 0 | free(apdu.resp); |
1008 | 2.70k | continue; /* read again with correct size */ |
1009 | 2.70k | } |
1010 | 18 | goto read_done; /* no more data to read */ |
1011 | 2.72k | } |
1012 | 1.89k | if (r == SC_ERROR_INCORRECT_PARAMETERS) |
1013 | 17 | goto read_done; |
1014 | 1.87k | free(buffer); |
1015 | 1.87k | if (apdu.resp != tmp) |
1016 | 0 | free(apdu.resp); |
1017 | 1.87k | LOG_FUNC_RETURN(ctx, r); /* arriving here means response error */ |
1018 | 1.87k | } |
1019 | | /* copy received data into buffer. realloc() if not enough space */ |
1020 | 7.04k | count = apdu.resplen; |
1021 | 7.04k | p = realloc(buffer, len + count); |
1022 | 7.04k | if (!p) { |
1023 | 0 | free(buffer); |
1024 | 0 | free((void *)apdu.data); |
1025 | 0 | if (apdu.resp != tmp) |
1026 | 0 | free(apdu.resp); |
1027 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1028 | 0 | } |
1029 | 7.04k | buffer = p; |
1030 | 7.04k | memcpy(buffer + len, apdu.resp, count); |
1031 | 7.04k | if (apdu.resp != tmp) { |
1032 | 0 | free(apdu.resp); |
1033 | 0 | apdu.resp = tmp; |
1034 | 0 | } |
1035 | 7.04k | len += count; |
1036 | 7.04k | if (count != card->max_recv_size) |
1037 | 1.58k | goto read_done; |
1038 | 7.04k | } |
1039 | | |
1040 | 1.62k | read_done: |
1041 | 1.62k | free((void *)apdu.data); |
1042 | 1.62k | if (apdu.resp != tmp) |
1043 | 0 | free(apdu.resp); |
1044 | | |
1045 | 1.62k | if (dnie_is_compressed(card, buffer, len)) { |
1046 | 129 | if (flags) |
1047 | 0 | *flags |= SC_FILE_FLAG_COMPRESSED_ZLIB; |
1048 | | /* Remove first 8 bytes with compression info*/ |
1049 | 129 | len -= 8; |
1050 | 129 | p = malloc(len); |
1051 | 129 | if (!p) { |
1052 | 0 | free(buffer); |
1053 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1054 | 0 | } |
1055 | 129 | memcpy(p, buffer + 8, len); |
1056 | 129 | free(buffer); |
1057 | 129 | buffer = p; |
1058 | 129 | } |
1059 | | |
1060 | | |
1061 | | /* ok: as final step, set correct cache data into dnie_priv structures */ |
1062 | 1.62k | GET_DNIE_PRIV_DATA(card)->cache = buffer; |
1063 | 1.62k | GET_DNIE_PRIV_DATA(card)->cachelen = len; |
1064 | 1.62k | sc_log(ctx, |
1065 | 1.62k | "fill_cache() done. length '%"SC_FORMAT_LEN_SIZE_T"u' bytes", |
1066 | 1.62k | len); |
1067 | 1.62k | LOG_FUNC_RETURN(ctx, (int)len); |
1068 | 1.62k | } |
1069 | | |
1070 | | /** |
1071 | | * OpenDNIe implementation of read_binary(). |
1072 | | * |
1073 | | * Reads a binary stream from card by mean of READ BINARY iso command |
1074 | | * Creates and handle a cache to allow data uncompression |
1075 | | * |
1076 | | * @param card pointer to sc_card_t structure |
1077 | | * @param idx offset from card file to ask data for |
1078 | | * @param buf where to store read data. must be non null |
1079 | | * @param count number of bytes to read |
1080 | | * @param flags. not used |
1081 | | * @return number of bytes read, 0 on EOF, error code on error |
1082 | | */ |
1083 | | static int dnie_read_binary(struct sc_card *card, |
1084 | | unsigned int idx, |
1085 | | u8 * buf, size_t count, unsigned long *flags) |
1086 | 14.2k | { |
1087 | 14.2k | size_t res = 0; |
1088 | 14.2k | int rc; |
1089 | 14.2k | sc_context_t *ctx = NULL; |
1090 | | /* preliminary checks */ |
1091 | 14.2k | if (!card || !card->ctx || !buf || (count <= 0)) |
1092 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1093 | 14.2k | ctx = card->ctx; |
1094 | | |
1095 | 14.2k | LOG_FUNC_CALLED(ctx); |
1096 | 14.2k | if (idx == 0 || GET_DNIE_PRIV_DATA(card)->cache == NULL) { |
1097 | | /* on first block or no cache, try to fill */ |
1098 | 7.75k | rc = dnie_fill_cache(card, flags); |
1099 | 7.75k | if (rc < 0) { |
1100 | 6.11k | sc_log(ctx, "Cannot fill cache. using iso_read_binary()"); |
1101 | 6.11k | return iso_ops->read_binary(card, idx, buf, count, flags); |
1102 | 6.11k | } |
1103 | 7.75k | } |
1104 | 8.14k | if (idx >= GET_DNIE_PRIV_DATA(card)->cachelen) |
1105 | 1.52k | return 0; /* at eof */ |
1106 | 6.62k | res = MIN(count, GET_DNIE_PRIV_DATA(card)->cachelen - idx); /* eval how many bytes to read */ |
1107 | 6.62k | memcpy(buf, GET_DNIE_PRIV_DATA(card)->cache + idx, res); /* copy data from buffer */ |
1108 | 6.62k | sc_log(ctx, "dnie_read_binary() '%zu' bytes", res); |
1109 | 6.62k | LOG_FUNC_RETURN(ctx, (int)res); |
1110 | 6.62k | } |
1111 | | |
1112 | | /** |
1113 | | * Send apdu to the card |
1114 | | * |
1115 | | * @param card pointer to sc_card_t structure |
1116 | | * @param path |
1117 | | * @param pathlen |
1118 | | * @param p1 |
1119 | | * @param file_out |
1120 | | * @return result |
1121 | | */ |
1122 | | static int dnie_compose_and_send_apdu(sc_card_t *card, const u8 *path, size_t pathlen, |
1123 | | u8 p1, sc_file_t **file_out) |
1124 | 19.5k | { |
1125 | 19.5k | int res = 0; |
1126 | 19.5k | sc_apdu_t apdu; |
1127 | 19.5k | u8 rbuf[MAX_RESP_BUFFER_SIZE]; |
1128 | 19.5k | sc_context_t *ctx = NULL; |
1129 | | |
1130 | 19.5k | if (!card || !card->ctx) |
1131 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1132 | 19.5k | ctx = card->ctx; |
1133 | | |
1134 | 19.5k | LOG_FUNC_CALLED(ctx); |
1135 | | |
1136 | 19.5k | dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, p1, 0, |
1137 | 19.5k | sc_get_max_recv_size(card), pathlen, |
1138 | 19.5k | rbuf, sizeof(rbuf), path, pathlen); |
1139 | 19.5k | if (p1 == 3) |
1140 | 0 | apdu.cse= SC_APDU_CASE_1; |
1141 | | |
1142 | 19.5k | if (file_out == NULL) |
1143 | 7.48k | apdu.cse = SC_APDU_CASE_4_SHORT; |
1144 | | |
1145 | 19.5k | res = sc_transmit_apdu(card, &apdu); |
1146 | 19.5k | if ((res != SC_SUCCESS) || (file_out == NULL)) |
1147 | 19.5k | LOG_TEST_RET(ctx, res, "SelectFile() APDU transmit failed"); |
1148 | 19.3k | if (file_out == NULL) { |
1149 | 7.37k | if (apdu.sw1 == 0x61) |
1150 | 0 | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, 0); |
1151 | 7.37k | SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, |
1152 | 7.37k | sc_check_sw(card, apdu.sw1, apdu.sw2)); |
1153 | 7.37k | } |
1154 | | |
1155 | | /* analyze response. if FCI, try to parse */ |
1156 | 11.9k | res = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1157 | 11.9k | if (res != SC_SUCCESS) { |
1158 | 6.91k | LOG_TEST_RET(ctx, res, "SelectFile() check_sw failed"); |
1159 | 6.91k | } |
1160 | 5.04k | if ((apdu.resplen < 2) || (apdu.resp[0] == 0x00)) { |
1161 | 246 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1162 | 246 | } |
1163 | | |
1164 | 4.80k | if (file_out) { |
1165 | | /* finally process FCI response */ |
1166 | 4.80k | size_t len = apdu.resp[1]; |
1167 | 4.80k | sc_file_free(*file_out); |
1168 | 4.80k | *file_out = sc_file_new(); |
1169 | 4.80k | if (*file_out == NULL) { |
1170 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); |
1171 | 0 | } |
1172 | 4.80k | if (apdu.resplen - 2 < len || len < 1) { |
1173 | 177 | LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); |
1174 | 177 | } |
1175 | 4.62k | res = card->ops->process_fci(card, *file_out, apdu.resp + 2, len); |
1176 | 4.62k | } |
1177 | 4.62k | LOG_FUNC_RETURN(ctx, res); |
1178 | 4.62k | } |
1179 | | |
1180 | | /** |
1181 | | * OpenDNIe implementation of Select_File(). |
1182 | | * |
1183 | | * Select_file: Does the equivalent of SELECT FILE command specified |
1184 | | * in ISO7816-4. Stores information about the selected file to |
1185 | | * <file>, if not NULL. |
1186 | | * |
1187 | | * SELECT file in DNIe is a bit tricky: |
1188 | | * - only handles some types: |
1189 | | * -- <strong>SC_PATH_TYPE_FILE_ID</strong> 2-byte long file ID |
1190 | | * -- <strong>SC_PATH_TYPE_DF_NAME</strong> named DF's |
1191 | | * -- <strong>SC_PATH_TYPE_PARENT</strong> jump to parent DF of current EF/DF - undocumented in DNIe manual |
1192 | | * -- other file types are marked as unsupported |
1193 | | * |
1194 | | * - Also MF must be addressed by their Name, not their ID |
1195 | | * So some magic is needed: |
1196 | | * - split <strong>SC_PATH_TYPE_PATH</strong> into several calls to each 2-byte data file ID |
1197 | | * - Translate initial file id 3F00 to be DF name 'Master.File' |
1198 | | * |
1199 | | * Also, Response always handle a proprietary FCI info, so |
1200 | | * need to handle it manually via dnie_process_fci() |
1201 | | * |
1202 | | * @param card Pointer to Card Structure |
1203 | | * @param in_path Path ID to be selected |
1204 | | * @param file_out where to store fci information |
1205 | | * @return SC_SUCCESS if ok; else error code |
1206 | | */ |
1207 | | static int dnie_select_file(struct sc_card *card, |
1208 | | const struct sc_path *in_path, |
1209 | | struct sc_file **file_out) |
1210 | 17.4k | { |
1211 | 17.4k | int res = SC_SUCCESS; |
1212 | 17.4k | sc_context_t *ctx = NULL; |
1213 | 17.4k | unsigned char tmp_path[sizeof(DNIE_MF_NAME)]; |
1214 | 17.4k | size_t reminder = 0; |
1215 | | |
1216 | 17.4k | if (!card || !card->ctx || !in_path) |
1217 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1218 | 17.4k | ctx = card->ctx; |
1219 | | |
1220 | 17.4k | LOG_FUNC_CALLED(ctx); |
1221 | | |
1222 | 17.4k | switch (in_path->type) { |
1223 | 1 | case SC_PATH_TYPE_FILE_ID: |
1224 | | /* pathlen must be of len=2 */ |
1225 | | /* |
1226 | | * gscriptor shows that DNIe also handles |
1227 | | * Select child DF (p1=1) and Select EF (p1=2), |
1228 | | * but we'll use P1=0 as general solution for all cases |
1229 | | * |
1230 | | * According iso7816-4 sect 7.1.1 pathlen==0 implies |
1231 | | * select MF, but this case is not supported by DNIe |
1232 | | */ |
1233 | 1 | if (in_path->len != 2) |
1234 | 1 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1235 | 1 | sc_log_hex(ctx, "select_file(ID)", in_path->value, in_path->len); |
1236 | 1 | res = dnie_compose_and_send_apdu(card, in_path->value, in_path->len, 0, file_out); |
1237 | 1 | break; |
1238 | 4.86k | case SC_PATH_TYPE_DF_NAME: |
1239 | 4.86k | sc_log_hex(ctx, "select_file(NAME)", in_path->value, in_path->len); |
1240 | 4.86k | res = dnie_compose_and_send_apdu(card, in_path->value, in_path->len, 4, file_out); |
1241 | 4.86k | break; |
1242 | 12.5k | case SC_PATH_TYPE_PATH: |
1243 | 12.5k | if ((in_path->len == 0) || ((in_path->len & 1) != 0)) /* not divisible by 2 */ |
1244 | 12.5k | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1245 | | |
1246 | 12.5k | sc_log_hex(ctx, "select_file(PATH): requested", in_path->value, in_path->len); |
1247 | | |
1248 | | /* convert to SC_PATH_TYPE_FILE_ID */ |
1249 | 12.5k | res = sc_lock(card); /* lock to ensure path traversal */ |
1250 | 12.5k | LOG_TEST_RET(ctx, res, "sc_lock() failed"); |
1251 | 12.5k | if (memcmp(in_path->value, "\x3F\x00", 2) == 0) { |
1252 | | /* if MF, use the name as path */ |
1253 | 10.7k | strcpy((char *)tmp_path, DNIE_MF_NAME); |
1254 | 10.7k | sc_log_hex(ctx, "select_file(NAME): requested", tmp_path, sizeof(DNIE_MF_NAME) - 1); |
1255 | 10.7k | res = dnie_compose_and_send_apdu(card, tmp_path, sizeof(DNIE_MF_NAME) - 1, 4, file_out); |
1256 | 10.7k | if (res != SC_SUCCESS) { |
1257 | 9.17k | sc_unlock(card); |
1258 | 9.17k | LOG_TEST_RET(ctx, res, "select_file(NAME) failed"); |
1259 | 9.17k | } |
1260 | 1.62k | tmp_path[2] = 0; |
1261 | 1.62k | reminder = in_path->len - 2; |
1262 | 1.73k | } else { |
1263 | 1.73k | tmp_path[2] = 0; |
1264 | 1.73k | reminder = in_path->len; |
1265 | 1.73k | } |
1266 | 6.30k | while (reminder > 0) { |
1267 | 3.91k | tmp_path[0] = in_path->value[in_path->len - reminder]; |
1268 | 3.91k | tmp_path[1] = in_path->value[1 + in_path->len - reminder]; |
1269 | 3.91k | sc_log(ctx, "select_file(PATH): requested:%s ", sc_dump_hex(tmp_path, 2)); |
1270 | 3.91k | res = dnie_compose_and_send_apdu(card, tmp_path, 2, 0, file_out); |
1271 | 3.91k | if (res != SC_SUCCESS) { |
1272 | 960 | sc_unlock(card); |
1273 | 960 | LOG_TEST_RET(ctx, res, "select_file(PATH) failed"); |
1274 | 960 | } |
1275 | 2.95k | reminder -= 2; |
1276 | 2.95k | } |
1277 | 2.39k | sc_unlock(card); |
1278 | 2.39k | break; |
1279 | 0 | case SC_PATH_TYPE_FROM_CURRENT: |
1280 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT); |
1281 | 0 | break; |
1282 | 0 | case SC_PATH_TYPE_PARENT: |
1283 | | /* Hey!! Manual doesn't says anything on this, but |
1284 | | * gscriptor shows that this type is supported |
1285 | | */ |
1286 | 0 | sc_log(ctx, "select_file(PARENT)"); |
1287 | | /* according iso7816-4 sect 7.1.1 shouldn't have any parameters */ |
1288 | 0 | if (in_path->len != 0) |
1289 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1290 | 0 | res = dnie_compose_and_send_apdu(card, NULL, 0, 3, file_out); |
1291 | 0 | break; |
1292 | 0 | default: |
1293 | 0 | LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); |
1294 | 0 | break; |
1295 | 17.4k | } |
1296 | | |
1297 | | /* as last step clear data cache and return */ |
1298 | 7.26k | dnie_clear_cache(GET_DNIE_PRIV_DATA(card)); |
1299 | 7.26k | LOG_FUNC_RETURN(ctx, res); |
1300 | 7.26k | } |
1301 | | |
1302 | | /** |
1303 | | * OpenDNIe implementation of Get_Challenge() command. |
1304 | | * |
1305 | | * Get challenge: retrieve 8 random bytes for any further use |
1306 | | * (eg perform an external authenticate command) |
1307 | | * |
1308 | | * NOTE: |
1309 | | * Official driver redundantly sets SM before execute this command |
1310 | | * No reason to do it, as is needed to do SM handshake... |
1311 | | * Also: official driver reads in blocks of 20 bytes. |
1312 | | * Why? Manual and iso-7816-4 states that only 8 bytes |
1313 | | * are required... so we will obey Manual |
1314 | | * |
1315 | | * @param card Pointer to card Structure |
1316 | | * @param rnd Where to store challenge |
1317 | | * @param len requested challenge length |
1318 | | * @return SC_SUCCESS if OK; else error code |
1319 | | */ |
1320 | | |
1321 | | static int dnie_get_challenge(struct sc_card *card, u8 * rnd, size_t len) |
1322 | 685 | { |
1323 | | /* As DNIe cannot handle other data length than 0x08 and 0x14 */ |
1324 | 685 | u8 rbuf[8]; |
1325 | 685 | size_t out_len; |
1326 | 685 | int r; |
1327 | | |
1328 | 685 | LOG_FUNC_CALLED(card->ctx); |
1329 | | |
1330 | 685 | r = iso_ops->get_challenge(card, rbuf, sizeof rbuf); |
1331 | 685 | LOG_TEST_RET(card->ctx, r, "GET CHALLENGE cmd failed"); |
1332 | | |
1333 | 611 | if (len < (size_t) r) { |
1334 | 2 | out_len = len; |
1335 | 609 | } else { |
1336 | 609 | out_len = (size_t) r; |
1337 | 609 | } |
1338 | 611 | memcpy(rnd, rbuf, out_len); |
1339 | | |
1340 | 611 | LOG_FUNC_RETURN(card->ctx, (int) out_len); |
1341 | 611 | } |
1342 | | |
1343 | | /* |
1344 | | * ISO 7816-8 functions |
1345 | | */ |
1346 | | |
1347 | | /** |
1348 | | * OpenDNIe implementation of Logout() card_driver function. |
1349 | | * |
1350 | | * Resets all access rights that were gained. Disable SM |
1351 | | * |
1352 | | * @param card Pointer to Card Structure |
1353 | | * @return SC_SUCCESS if OK; else error code |
1354 | | */ |
1355 | | static int dnie_logout(struct sc_card *card) |
1356 | 0 | { |
1357 | 0 | int result = SC_SUCCESS; |
1358 | 0 | sc_file_t *file = NULL; |
1359 | |
|
1360 | 0 | if ((card == NULL) || (card->ctx == NULL)) |
1361 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1362 | | |
1363 | 0 | LOG_FUNC_CALLED(card->ctx); |
1364 | 0 | if (card->sm_ctx.sm_mode != SM_MODE_NONE) { |
1365 | | /* mark the channel as closed */ |
1366 | 0 | result = cwa_create_secure_channel(card, |
1367 | 0 | GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_OFF); |
1368 | 0 | LOG_TEST_RET(card->ctx, result, "Cannot close the secure channel"); |
1369 | | /* request the Master File to provoke an SM error and close the channel */ |
1370 | 0 | result = dnie_compose_and_send_apdu(card, (const u8 *) DNIE_MF_NAME, |
1371 | 0 | sizeof(DNIE_MF_NAME) - 1, 4, &file); |
1372 | 0 | if (result == SC_ERROR_SM) |
1373 | 0 | result = SC_SUCCESS; |
1374 | 0 | } |
1375 | | |
1376 | 0 | if (file != NULL) |
1377 | 0 | sc_file_free(file); |
1378 | 0 | LOG_FUNC_RETURN(card->ctx, result); |
1379 | 0 | } |
1380 | | |
1381 | | /** |
1382 | | * Implementation of Set_Security_Environment card driver command. |
1383 | | * |
1384 | | * Initializes the security environment on card |
1385 | | * according to <env>, and stores the environment as <se_num> on the |
1386 | | * card. If se_num <= 0, the environment will not be stored. |
1387 | | * Notice that OpenDNIe SM handling requires a buffer longer than |
1388 | | * provided for this command; so special apdu is used in cwa code |
1389 | | * |
1390 | | * @param card Pointer to card driver Structure |
1391 | | * @param env Pointer to security environment data |
1392 | | * @param num: which Card Security environment to use (ignored in OpenDNIe) |
1393 | | * @return SC_SUCCESS if OK; else error code |
1394 | | * |
1395 | | * TODO: mix these code with SM set_security_env operations |
1396 | | * |
1397 | | */ |
1398 | | static int dnie_set_security_env(struct sc_card *card, |
1399 | | const struct sc_security_env *env, int se_num) |
1400 | 0 | { |
1401 | 0 | sc_apdu_t apdu; |
1402 | 0 | u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; /* buffer to compose apdu data */ |
1403 | 0 | u8 rbuf[MAX_RESP_BUFFER_SIZE]; |
1404 | 0 | u8 *p = sbuf; |
1405 | 0 | int result = SC_SUCCESS; |
1406 | 0 | if ((card == NULL) || (card->ctx == NULL) || (env == NULL)) |
1407 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1408 | 0 | LOG_FUNC_CALLED(card->ctx); |
1409 | 0 | if (se_num!=0) { |
1410 | 0 | sc_log(card->ctx,"DNIe cannot handle several security envs"); |
1411 | 0 | LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS); |
1412 | 0 | } |
1413 | | |
1414 | | /* Secure Channel should be on here, if not means an error */ |
1415 | | /* |
1416 | | result = |
1417 | | cwa_create_secure_channel(card, dnie_priv.provider, CWA_SM_WARM); |
1418 | | LOG_TEST_RET(card->ctx, result, |
1419 | | "set_security_env(); Cannot establish SM"); |
1420 | | */ |
1421 | | |
1422 | | /* check for algorithms */ |
1423 | 0 | if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) { |
1424 | 0 | sc_log(card->ctx, "checking algorithms"); |
1425 | 0 | switch (env->algorithm) { |
1426 | 0 | case SC_ALGORITHM_RSA: |
1427 | 0 | result = SC_SUCCESS; |
1428 | 0 | break; |
1429 | 0 | case SC_ALGORITHM_EC: |
1430 | 0 | case SC_ALGORITHM_GOSTR3410: |
1431 | 0 | default: |
1432 | 0 | result = SC_ERROR_NOT_SUPPORTED; |
1433 | 0 | break; |
1434 | 0 | } |
1435 | 0 | LOG_TEST_RET(card->ctx, result, "Unsupported algorithm"); |
1436 | 0 | if ((env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) == 0) { |
1437 | 0 | result = SC_ERROR_NOT_SUPPORTED; |
1438 | | /* TODO: |
1439 | | * Manual says that only RSA with SHA1 is supported, but found |
1440 | | * some docs where states that SHA256 is also handled |
1441 | | */ |
1442 | 0 | } |
1443 | 0 | LOG_TEST_RET(card->ctx, result, |
1444 | 0 | "Only RSA with SHA1 is supported"); |
1445 | | /* ok: insert algorithm reference into buffer */ |
1446 | 0 | *p++ = 0x80; /* algorithm reference tag */ |
1447 | 0 | *p++ = 0x01; /* len */ |
1448 | 0 | *p++ = env->algorithm_ref & 0xff; /* val */ |
1449 | 0 | } |
1450 | | |
1451 | | /* check for key references */ |
1452 | 0 | if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { |
1453 | 0 | sc_log(card->ctx, "checking key references"); |
1454 | 0 | if (env->key_ref_len != 1) { |
1455 | 0 | sc_log(card->ctx, "Null or invalid key ID reference"); |
1456 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1457 | 0 | } |
1458 | 0 | sc_log(card->ctx, "Using key reference '%s'", |
1459 | 0 | sc_dump_hex(env->key_ref, env->key_ref_len)); |
1460 | | /* ok: insert key reference into buffer */ |
1461 | | /* notice that DNIe uses same key reference for pubk and privk */ |
1462 | | |
1463 | | /* see cwa14890-2 sect B.1 about Control Reference Template Tags */ |
1464 | 0 | *p++ = 0x84; /* TODO: make proper detection of 0x83 /0x84 tag usage */ |
1465 | 0 | *p++ = 0x02; /* len */ |
1466 | 0 | *p++ = 0x01; /* key ID prefix (MSB byte of keyFile ID) */ |
1467 | 0 | memcpy(p, env->key_ref, env->key_ref_len); /* in DNIe key_ref_len=1 */ |
1468 | 0 | p += env->key_ref_len; |
1469 | | /* store key reference into private data */ |
1470 | 0 | GET_DNIE_PRIV_DATA(card)->rsa_key_ref = 0xff & env->key_ref[0]; |
1471 | 0 | } |
1472 | | |
1473 | | /* create and format apdu */ |
1474 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x22, 0x00, 0x00, 255, p - sbuf, |
1475 | 0 | rbuf, MAX_RESP_BUFFER_SIZE, sbuf, p - sbuf); |
1476 | | |
1477 | | /* check and perform operation */ |
1478 | 0 | switch (env->operation) { |
1479 | 0 | case SC_SEC_OPERATION_DECIPHER: |
1480 | | /* TODO: Manual is unsure about if (de)cipher() is supported */ |
1481 | 0 | apdu.p1 = 0xC1; |
1482 | 0 | apdu.p2 = 0xB8; |
1483 | 0 | break; |
1484 | 0 | case SC_SEC_OPERATION_SIGN: |
1485 | 0 | apdu.p1 = 0x41; /* SET; internal operation */ |
1486 | 0 | apdu.p2 = 0xB6; /* Template for Digital Signature */ |
1487 | 0 | break; |
1488 | 0 | default: |
1489 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1490 | 0 | } |
1491 | | |
1492 | | /* Notice that Manual states that DNIE only allows handle of |
1493 | | * current security environment, so se_num is ignored, and |
1494 | | * store sec env apdu (00 22 F2 se_num) command will not be issued */ |
1495 | | |
1496 | | /* send composed apdu and parse result */ |
1497 | 0 | result = sc_transmit_apdu(card, &apdu); |
1498 | 0 | LOG_TEST_RET(card->ctx, result, "Set Security Environment failed"); |
1499 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1500 | |
|
1501 | 0 | LOG_FUNC_RETURN(card->ctx, result); |
1502 | 0 | } |
1503 | | |
1504 | | /** |
1505 | | * OpenDNIe implementation of Decipher() card driver operation. |
1506 | | * |
1507 | | * Engages the deciphering operation. Card will use the |
1508 | | * security environment set in a call to set_security_env or |
1509 | | * restore_security_env. |
1510 | | * |
1511 | | * Notice that DNIe manual doesn't say anything about crypt/decrypt |
1512 | | * operations. So this code is based on ISO standards and still needs |
1513 | | * to be checked |
1514 | | * |
1515 | | * ADD: seems that DNIe supports a minimal cipher/decipher operation |
1516 | | * but restricted to 1024 data chunks . Need more info and tests |
1517 | | * |
1518 | | * @param card Pointer to Card Driver Structure |
1519 | | * @param crgram cryptogram to be (de)ciphered |
1520 | | * @param crgram_len cryptogram length |
1521 | | * @param out where to store result |
1522 | | * @param outlen length of result buffer |
1523 | | * @return SC_SUCCESS if OK; else error code |
1524 | | */ |
1525 | | static int dnie_decipher(struct sc_card *card, |
1526 | | const u8 * crgram, size_t crgram_len, |
1527 | | u8 * out, size_t outlen) |
1528 | 0 | { |
1529 | 0 | struct sc_apdu apdu; |
1530 | 0 | u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; |
1531 | 0 | u8 sbuf[MAX_RESP_BUFFER_SIZE]; |
1532 | 0 | size_t len; |
1533 | 0 | int result = SC_SUCCESS; |
1534 | 0 | if ((card == NULL) || (card->ctx == NULL)) |
1535 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1536 | 0 | LOG_FUNC_CALLED(card->ctx); |
1537 | 0 | if ((crgram == NULL) || (out == NULL) || (crgram_len > 255)) { |
1538 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1539 | 0 | } |
1540 | | /* Secure Channel should be on. Elsewhere an error will be thrown */ |
1541 | | /* |
1542 | | result = |
1543 | | cwa_create_secure_channel(card, dnie_priv.provider, CWA_SM_WARM); |
1544 | | LOG_TEST_RET(card->ctx, result, "decipher(); Cannot establish SM"); |
1545 | | */ |
1546 | | |
1547 | | /* Official driver uses an undocumented proprietary APDU |
1548 | | * (90 74 40 keyID). This code uses standard 00 2A 80 8x one) |
1549 | | * as shown in card-atrust-acos.c and card-jcop.c |
1550 | | */ |
1551 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, |
1552 | 0 | 0x2A, /* INS: 0x2A perform security operation */ |
1553 | 0 | 0x80, /* P1: Response is plain value */ |
1554 | 0 | 0x86, /* P2: 8x: Padding indicator byte followed by cryptogram */ |
1555 | 0 | 256, crgram_len + 1, rbuf, sizeof(rbuf), sbuf, crgram_len + 1 |
1556 | 0 | ); |
1557 | |
|
1558 | 0 | sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */ |
1559 | 0 | memcpy(sbuf + 1, crgram, crgram_len); |
1560 | | /* send apdu */ |
1561 | 0 | result = sc_transmit_apdu(card, &apdu); |
1562 | 0 | LOG_TEST_RET(card->ctx, result, "APDU transmit failed"); |
1563 | | /* check response */ |
1564 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1565 | 0 | LOG_TEST_RET(card->ctx, result, "decipher returned error"); |
1566 | | /* responde ok: fill result data and return */ |
1567 | 0 | len = apdu.resplen > outlen ? outlen : apdu.resplen; |
1568 | 0 | memcpy(out, apdu.resp, len); |
1569 | 0 | LOG_FUNC_RETURN(card->ctx, result); |
1570 | 0 | } |
1571 | | |
1572 | | /** |
1573 | | * OpenDNIe implementation of Compute_Signature() card driver operation. |
1574 | | * |
1575 | | * Generates a digital signature on the card. |
1576 | | * This function handles the process of hash + sign |
1577 | | * with previously selected keys (by mean of set_security environment |
1578 | | * |
1579 | | * AS iso7816 and DNIe Manual states there are 3 ways to perform |
1580 | | * this operation: |
1581 | | * |
1582 | | * - (plaintext) Hash on plaintext + sign |
1583 | | * - (partial hash) Send a externally evaluated pkcs1 hash + sign |
1584 | | * - (hash) directly sign a given sha1 hash |
1585 | | * |
1586 | | * So the code analyze incoming data, decide which method to be used |
1587 | | * and applies |
1588 | | * |
1589 | | * @param card pointer to sc_card_t structure |
1590 | | * @param data data to be hashed/signed |
1591 | | * @param datalen length of provided data |
1592 | | * @param out buffer to store results into |
1593 | | * @param outlen available space in result buffer |
1594 | | * @return |
1595 | | * - Positive value: Size of data stored in out buffer when no error |
1596 | | * - Negative value: error code |
1597 | | */ |
1598 | | static int dnie_compute_signature(struct sc_card *card, |
1599 | | const u8 * data, size_t datalen, |
1600 | | u8 * out, size_t outlen) |
1601 | 0 | { |
1602 | 0 | int result = SC_SUCCESS; |
1603 | 0 | size_t result_resplen = 0; |
1604 | 0 | struct sc_apdu apdu; |
1605 | 0 | u8 rbuf[MAX_RESP_BUFFER_SIZE]; /* to receive sign response */ |
1606 | | |
1607 | | /* some preliminary checks */ |
1608 | 0 | if ((card == NULL) || (card->ctx == NULL)) |
1609 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1610 | | /* OK: start working */ |
1611 | 0 | LOG_FUNC_CALLED(card->ctx); |
1612 | | /* more checks */ |
1613 | 0 | if ((data == NULL) || (out == NULL)) |
1614 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1615 | 0 | if (datalen > SC_MAX_APDU_BUFFER_SIZE) /* should be 256 */ |
1616 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1617 | | |
1618 | | #ifdef ENABLE_DNIE_UI |
1619 | | /* (Requested by DGP): on signature operation, ask user consent */ |
1620 | | if (GET_DNIE_PRIV_DATA(card)->rsa_key_ref == 0x02) { /* TODO: revise key ID handling */ |
1621 | | result = dnie_ask_user_consent(card,user_consent_title,user_consent_message); |
1622 | | LOG_TEST_RET(card->ctx, result, "User consent denied"); |
1623 | | } |
1624 | | #endif |
1625 | | |
1626 | | /* |
1627 | | Seems that OpenSC already provides pkcs#1 v1.5 DigestInfo structure |
1628 | | with pre-calculated hash. So no need to to any Hash calculation, |
1629 | | |
1630 | | So just extract 15+20 DigestInfo+Hash info from ASN.1 provided |
1631 | | data and feed them into sign() command |
1632 | | */ |
1633 | 0 | sc_log_hex(card->ctx, |
1634 | 0 | "Compute signature\n============================================================", |
1635 | 0 | data, datalen); |
1636 | | |
1637 | | /*INS: 0x2A PERFORM SECURITY OPERATION |
1638 | | * P1: 0x9E Resp: Digital Signature |
1639 | | * P2: 0x9A Cmd: Input for Digital Signature */ |
1640 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A, 256, datalen, |
1641 | 0 | rbuf, sizeof(rbuf), data, datalen); |
1642 | | /* tell card to compute signature */ |
1643 | 0 | result = sc_transmit_apdu(card, &apdu); |
1644 | 0 | if (result != SC_SUCCESS) { |
1645 | 0 | LOG_TEST_RET(card->ctx, result, "compute_signature() failed"); |
1646 | 0 | } |
1647 | | /* check response */ |
1648 | 0 | result = sc_check_sw(card, apdu.sw1, apdu.sw2); |
1649 | 0 | if (result != SC_SUCCESS) { |
1650 | 0 | LOG_TEST_RET(card->ctx, result, "compute_signature() response error"); |
1651 | 0 | } |
1652 | | |
1653 | | /* ok: copy result from buffer */ |
1654 | 0 | result_resplen = apdu.resplen; |
1655 | 0 | if (outlen < result_resplen) |
1656 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1657 | 0 | memcpy(out, apdu.resp, result_resplen); |
1658 | | /* and return response length */ |
1659 | 0 | LOG_FUNC_RETURN(card->ctx, (int)result_resplen); |
1660 | 0 | } |
1661 | | |
1662 | | /* |
1663 | | * ISO 7816-9 functions |
1664 | | */ |
1665 | | |
1666 | | /** |
1667 | | * OpenDNIe implementation of List_Files() card driver operation. |
1668 | | * |
1669 | | * List available files in current DF |
1670 | | * This is a dirty and trick implementation: |
1671 | | * Just try every ID in current dir |
1672 | | * |
1673 | | * @param card Pointer to Card Driver structure |
1674 | | * @param buff buffer to store result into |
1675 | | * @param bufflen size of provided buffer |
1676 | | * @return SC_SUCCESS if OK; else error code |
1677 | | * |
1678 | | * TODO: check for presence of every file ids on a DF is not |
1679 | | * practical. Locate a better way to handle, or remove code |
1680 | | */ |
1681 | | static int dnie_list_files(sc_card_t * card, u8 * buf, size_t buflen) |
1682 | 37 | { |
1683 | 37 | int res = SC_SUCCESS; |
1684 | 37 | int id1 = 0; |
1685 | 37 | int id2 = 0; |
1686 | 37 | size_t count = 0; |
1687 | 37 | u8 data[2]; |
1688 | 37 | sc_apdu_t apdu; |
1689 | 37 | if (!card || !card->ctx) |
1690 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1691 | | |
1692 | 37 | LOG_FUNC_CALLED(card->ctx); |
1693 | 37 | if (!buf || (buflen < 2)) |
1694 | 37 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1695 | | |
1696 | | /* compose select_file(ID) command */ |
1697 | 37 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00, 0, 2, |
1698 | 37 | NULL, 0, data, 2); |
1699 | | /* iterate on every possible ids */ |
1700 | 37 | for (id1 = 0; id1 < 256; id1++) { |
1701 | 37 | for (id2 = 0; id2 < 256; id2++) { |
1702 | 37 | if (count >= (buflen - 2)) { |
1703 | 0 | sc_log(card->ctx, |
1704 | 0 | "list_files: end of buffer. Listing stopped"); |
1705 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1706 | 0 | } |
1707 | | /* according iso several ids are not allowed, so check for it */ |
1708 | 37 | if ((id1 == 0x3F) && (id2 == 0xFF)) |
1709 | 0 | continue; /* generic parent "." DF */ |
1710 | 37 | if ((id1 == 0x2F) && (id2 == 0x00)) |
1711 | 0 | continue; /* RFU see iso 8.2.1.1 */ |
1712 | 37 | if ((id1 == 0x2F) && (id2 == 0x01)) |
1713 | 0 | continue; /* RFU */ |
1714 | | /* compose and transmit select_file() cmd */ |
1715 | 37 | data[0] = (u8) (0xff & id1); |
1716 | 37 | data[1] = (u8) (0xff & id2); |
1717 | 37 | res = sc_transmit_apdu(card, &apdu); |
1718 | 37 | if (res != SC_SUCCESS) { |
1719 | 37 | sc_log(card->ctx, "List file '%02X%02X' failed", |
1720 | 37 | id1, id2); |
1721 | | /* if file not found, continue; else abort */ |
1722 | 37 | if (res != SC_ERROR_FILE_NOT_FOUND) |
1723 | 37 | LOG_FUNC_RETURN(card->ctx, res); |
1724 | 0 | continue; |
1725 | 37 | } |
1726 | | /* if file found, process fci to get file type */ |
1727 | 0 | sc_log(card->ctx, "Found File ID '%02X%02X'", id1, id2); |
1728 | | /* store id into buffer */ |
1729 | 0 | *(buf + count++) = data[0]; |
1730 | 0 | *(buf + count++) = data[1]; |
1731 | | /* TODO: |
1732 | | * if found file is a DF go back to parent DF |
1733 | | * to continue search */ |
1734 | 0 | } |
1735 | 37 | } |
1736 | | /* arriving here means all done */ |
1737 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1738 | 0 | } |
1739 | | |
1740 | | /** |
1741 | | * Parse APDU results to generate proper error code. |
1742 | | * |
1743 | | * Traps standard check_sw function to take care on special error codes |
1744 | | * for OpenDNIe (mostly related to SM status and operations) |
1745 | | * |
1746 | | * @param card Pointer to Card driver Structure |
1747 | | * @param sw1 SW1 APDU response byte |
1748 | | * @param sw2 SW2 APDU response byte |
1749 | | * @return SC_SUCCESS if no error; else proper error code |
1750 | | */ |
1751 | | static int dnie_check_sw(struct sc_card *card, |
1752 | | unsigned int sw1, unsigned int sw2) |
1753 | 35.4k | { |
1754 | 35.4k | int res = SC_SUCCESS; |
1755 | 35.4k | int n = 0; |
1756 | 35.4k | if (!card || !card->ctx) |
1757 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1758 | 35.4k | LOG_FUNC_CALLED(card->ctx); |
1759 | | |
1760 | | /* check specific dnie errors */ |
1761 | 141k | for (n = 0; dnie_errors[n].SWs != 0; n++) { |
1762 | 106k | if (dnie_errors[n].SWs == ((sw1 << 8) | sw2)) { |
1763 | 116 | sc_log(card->ctx, "%s", dnie_errors[n].errorstr); |
1764 | 116 | return dnie_errors[n].errorno; |
1765 | 116 | } |
1766 | 106k | } |
1767 | | |
1768 | | /* arriving here means check for supported iso error codes */ |
1769 | 35.3k | res = iso_ops->check_sw(card, sw1, sw2); |
1770 | 35.3k | LOG_FUNC_RETURN(card->ctx, res); |
1771 | 35.3k | } |
1772 | | |
1773 | | /** |
1774 | | * OpenDNIe implementation for Card_Ctl() card driver operation. |
1775 | | * |
1776 | | * This command provides access to non standard functions provided by |
1777 | | * this card driver, as defined in cardctl.h |
1778 | | * |
1779 | | * @param card Pointer to card driver structure |
1780 | | * @param request Operation requested |
1781 | | * @param data where to get data/store response |
1782 | | * @return SC_SUCCESS if ok; else error code |
1783 | | * @see cardctl.h |
1784 | | * |
1785 | | * TODO: wait for GET_CARD_INFO generic cardctl to be implemented |
1786 | | * in opensc and rewrite code according it |
1787 | | */ |
1788 | | static int dnie_card_ctl(struct sc_card *card, |
1789 | | unsigned long request, void *data) |
1790 | 343 | { |
1791 | 343 | int result = SC_SUCCESS; |
1792 | 343 | if ((card == NULL) || (card->ctx == NULL)) |
1793 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1794 | 343 | LOG_FUNC_CALLED(card->ctx); |
1795 | 343 | if (data == NULL) { |
1796 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
1797 | 0 | } |
1798 | 343 | switch (request) { |
1799 | | /* obtain lifecycle status by reading card->type */ |
1800 | 132 | case SC_CARDCTL_LIFECYCLE_GET: |
1801 | 132 | switch (card->type) { |
1802 | 0 | case SC_CARD_TYPE_DNIE_ADMIN: |
1803 | 0 | result = SC_CARDCTRL_LIFECYCLE_ADMIN; |
1804 | 0 | break; |
1805 | 132 | case SC_CARD_TYPE_DNIE_USER: |
1806 | 132 | result = SC_CARDCTRL_LIFECYCLE_USER; |
1807 | 132 | break; |
1808 | 0 | case SC_CARD_TYPE_DNIE_BLANK: |
1809 | 0 | case SC_CARD_TYPE_DNIE_TERMINATED: |
1810 | 0 | result = SC_CARDCTRL_LIFECYCLE_OTHER; |
1811 | 0 | break; |
1812 | 132 | } |
1813 | 132 | *(int *)data = result; |
1814 | 132 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
1815 | | /* call card to obtain serial number */ |
1816 | 133 | case SC_CARDCTL_GET_SERIALNR: |
1817 | 133 | result = dnie_get_serialnr(card, (sc_serial_number_t *) data); |
1818 | 133 | LOG_FUNC_RETURN(card->ctx, result); |
1819 | 0 | case SC_CARDCTL_DNIE_GENERATE_KEY: |
1820 | | /* some reports says that this card supports genkey */ |
1821 | 0 | result = dnie_generate_key(card, data); |
1822 | 0 | LOG_FUNC_RETURN(card->ctx, result); |
1823 | 0 | case SC_CARDCTL_DNIE_GET_INFO: |
1824 | | /* retrieve name, surname and eid number */ |
1825 | 0 | result = dnie_get_info(card, data); |
1826 | 0 | LOG_FUNC_RETURN(card->ctx, result); |
1827 | 78 | default: |
1828 | | /* default: unsupported function */ |
1829 | 78 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
1830 | 343 | } |
1831 | 343 | } |
1832 | | |
1833 | | /** |
1834 | | * Read first bytes of an EF to check for compression data. |
1835 | | * |
1836 | | * FCI info on compressed files provides the length of the compressed |
1837 | | * data. When fci returns filetype = 0x24, needs to check if the |
1838 | | * file is compressed, and set up properly correct file length, to let |
1839 | | * the read_binary() file cache work |
1840 | | * |
1841 | | * Extract real file length from compressed file is done by mean of |
1842 | | * reading 8 first bytes for uncompressed/compressed length. |
1843 | | * Lengths are provided as two 4-byte little endian numbers |
1844 | | * |
1845 | | * Implemented just like a direct read binary apdu bypassing dnie file cache |
1846 | | * |
1847 | | * @param card sc_card_t structure pointer |
1848 | | * @return <0: error code - ==0 not compressed - >0 file size |
1849 | | */ |
1850 | | static int dnie_read_header(struct sc_card *card) |
1851 | 908 | { |
1852 | 908 | sc_apdu_t apdu; |
1853 | 908 | int r; |
1854 | 908 | u8 buf[MAX_RESP_BUFFER_SIZE]; |
1855 | 908 | unsigned long uncompressed = 0L; |
1856 | 908 | unsigned long compressed = 0L; |
1857 | 908 | sc_context_t *ctx = NULL; |
1858 | | |
1859 | 908 | if (!card || !card->ctx) |
1860 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1861 | 908 | ctx = card->ctx; |
1862 | 908 | LOG_FUNC_CALLED(ctx); |
1863 | | |
1864 | | /* initialize apdu */ |
1865 | 908 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, 0x00, 0x00, 8, 0, |
1866 | 908 | buf, MAX_RESP_BUFFER_SIZE, NULL, 0); |
1867 | | /* transmit apdu */ |
1868 | 908 | r = sc_transmit_apdu(card, &apdu); |
1869 | 908 | if (r != SC_SUCCESS) { |
1870 | 75 | sc_log(ctx, "read_header() APDU transmit failed"); |
1871 | 75 | LOG_FUNC_RETURN(ctx, r); |
1872 | 75 | } |
1873 | | /* check response */ |
1874 | 833 | if (apdu.resplen != 8) |
1875 | 316 | goto header_notcompressed; |
1876 | 517 | uncompressed = lebytes2ulong(apdu.resp); |
1877 | 517 | compressed = lebytes2ulong(apdu.resp + 4); |
1878 | 517 | if (uncompressed < compressed) |
1879 | 121 | goto header_notcompressed; |
1880 | 396 | if (uncompressed > 32767) |
1881 | 231 | goto header_notcompressed; |
1882 | | /* ok: assume data is correct */ |
1883 | 165 | sc_log(ctx, "read_header: uncompressed file size is %lu", uncompressed); |
1884 | 165 | return (int)(0x7FFF & uncompressed); |
1885 | | |
1886 | 668 | header_notcompressed: |
1887 | 668 | sc_log(ctx, "response doesn't match compressed file header"); |
1888 | 668 | return 0; |
1889 | 396 | } |
1890 | | |
1891 | | /** |
1892 | | * Access control list bytes for proprietary DNIe FCI response for DF's. |
1893 | | * based in information from official DNIe Driver |
1894 | | * Parsing code based on itacns card driver |
1895 | | */ |
1896 | | static int df_acl[] = { /* to handle DF's */ |
1897 | | SC_AC_OP_CREATE, SC_AC_OP_DELETE, |
1898 | | SC_AC_OP_REHABILITATE, SC_AC_OP_INVALIDATE, |
1899 | | -1 /* !hey!, what about 5th byte of FCI info? */ |
1900 | | }; |
1901 | | |
1902 | | /** |
1903 | | * Access control list bytes for proprietary DNIe FCI response for EF's. |
1904 | | * based in information from official DNIe Driver |
1905 | | * Parsing code based on itacns card driver |
1906 | | */ |
1907 | | static int ef_acl[] = { /* to handle EF's */ |
1908 | | SC_AC_OP_READ, SC_AC_OP_UPDATE, |
1909 | | SC_AC_OP_REHABILITATE, SC_AC_OP_INVALIDATE, |
1910 | | -1 /* !hey!, what about 5th byte of FCI info? */ |
1911 | | }; |
1912 | | |
1913 | | /** |
1914 | | * OpenDNIe implementation of Process_FCI() card driver command. |
1915 | | * |
1916 | | * Parse SelectFile's File Control information. |
1917 | | * - First, std iso_parse_fci is called to parse std fci tags |
1918 | | * - Then analyze proprietary tag according DNIe Manual |
1919 | | * |
1920 | | * @param card OpenSC card structure pointer |
1921 | | * @param file currently selected EF or DF |
1922 | | * @param buf received FCI data |
1923 | | * @param buflen FCI length |
1924 | | * @return SC_SUCCESS if OK; else error code |
1925 | | */ |
1926 | | static int dnie_process_fci(struct sc_card *card, |
1927 | | struct sc_file *file, const u8 * buf, size_t buflen) |
1928 | 4.62k | { |
1929 | 4.62k | int res = SC_SUCCESS; |
1930 | 4.62k | int *op = df_acl; |
1931 | 4.62k | int n = 0; |
1932 | 4.62k | sc_context_t *ctx = NULL; |
1933 | 4.62k | if ((card == NULL) || (card->ctx == NULL) || (file == NULL) || buflen == 0) |
1934 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1935 | 4.62k | ctx = card->ctx; |
1936 | 4.62k | LOG_FUNC_CALLED(ctx); |
1937 | | /* first of all, let iso do the hard work */ |
1938 | 4.62k | res = iso_ops->process_fci(card, file, buf, buflen); |
1939 | 4.62k | LOG_TEST_RET(ctx, res, "iso7816_process_fci() failed"); |
1940 | | /* if tag 0x85 is received, then file->prop_attr_len should be filled |
1941 | | * by sc_file_set_prop_attr() code. So check and set data according manual |
1942 | | * Note errata at pg 35 of Manual about DF identifier (should be 0x38) */ |
1943 | 4.62k | if (file->prop_attr_len == 0) { /* no proprietary tag (0x85) received */ |
1944 | 3.06k | res = SC_SUCCESS; |
1945 | 3.06k | goto dnie_process_fci_end; |
1946 | 3.06k | } |
1947 | | /* at least 10 bytes should be received */ |
1948 | 1.56k | if (file->prop_attr_len < 10) { |
1949 | 57 | res = SC_ERROR_WRONG_LENGTH; |
1950 | 57 | goto dnie_process_fci_end; |
1951 | 57 | } |
1952 | | /* byte 0 denotes file type */ |
1953 | 1.50k | switch (file->prop_attr[0]) { |
1954 | 118 | case 0x01: /* EF for plain files */ |
1955 | 118 | file->type = SC_FILE_TYPE_WORKING_EF; |
1956 | 118 | file->ef_structure = SC_FILE_EF_TRANSPARENT; |
1957 | 118 | break; |
1958 | 323 | case 0x15: /* EF for keys: linear variable simple TLV */ |
1959 | 323 | file->type = SC_FILE_TYPE_WORKING_EF; |
1960 | | /* pin file 3F000000 has also this EF type */ |
1961 | 323 | if ( ( file->prop_attr[2] == 0x00 ) && (file->prop_attr[3] == 0x00 ) ) { |
1962 | 88 | sc_log(ctx,"Processing pin EF"); |
1963 | 88 | break; |
1964 | 88 | } |
1965 | | /* FCI response for Keys EF returns 3 additional bytes */ |
1966 | 235 | if (file->prop_attr_len < 13) { |
1967 | 63 | sc_log(ctx, "FCI response len for Keys EF should be 13 bytes"); |
1968 | 63 | res = SC_ERROR_WRONG_LENGTH; |
1969 | 63 | goto dnie_process_fci_end; |
1970 | 63 | } |
1971 | 172 | break; |
1972 | 908 | case 0x24: /* EF for compressed certificates */ |
1973 | 908 | file->type = SC_FILE_TYPE_WORKING_EF; |
1974 | 908 | file->ef_structure = SC_FILE_EF_TRANSPARENT; |
1975 | | /* evaluate real length by reading first 8 bytes from file */ |
1976 | 908 | res = dnie_read_header(card); |
1977 | | /* Hey!, we need pin to read certificates... */ |
1978 | 908 | if (res == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) |
1979 | 5 | goto dnie_process_fci_end; |
1980 | 903 | if (res <= 0) { |
1981 | 742 | sc_log(ctx, |
1982 | 742 | "Cannot evaluate uncompressed size. use fci length"); |
1983 | 742 | } else { |
1984 | 161 | sc_log(ctx, "Storing uncompressed size '%d' into fci", |
1985 | 161 | res); |
1986 | 161 | file->prop_attr[3] = (u8) ((res >> 8) & 0xff); |
1987 | 161 | file->prop_attr[4] = (u8) (res & 0xff); |
1988 | 161 | } |
1989 | 903 | break; |
1990 | 103 | case 0x38: /* Errata: manual page 35 says wrong 0x34 */ |
1991 | 103 | file->type = SC_FILE_TYPE_DF; |
1992 | 103 | break; |
1993 | 52 | default: |
1994 | 52 | res = SC_ERROR_UNKNOWN_DATA_RECEIVED; |
1995 | 52 | goto dnie_process_fci_end; |
1996 | 1.50k | } |
1997 | | |
1998 | | /* bytes 1 and 2 stores file ID */ |
1999 | 1.38k | file->id = ( ( 0xff & (int)file->prop_attr[1] ) << 8 ) | |
2000 | 1.38k | ( 0xff & (int)file->prop_attr[2] ) ; |
2001 | | |
2002 | | /* bytes 3 and 4 states file length */ |
2003 | 1.38k | file->size = ( ( 0xff & (int)file->prop_attr[3] ) << 8 ) | |
2004 | 1.38k | ( 0xff & (int)file->prop_attr[4] ) ; |
2005 | | |
2006 | | /* bytes 5 to 9 states security attributes */ |
2007 | | /* NOTE: |
2008 | | * seems that these 5 bytes are handled according iso7816-9 sect 8. |
2009 | | * but sadly that each card uses their own bits :-( |
2010 | | * Moreover: Manual talks on 5 bytes, but official driver only uses 4 |
2011 | | * No info available (yet), so copy code from card-jcos.c / card-flex.c |
2012 | | * card drivers and pray... */ |
2013 | 1.38k | op = (file->type == SC_FILE_TYPE_DF) ? df_acl : ef_acl; |
2014 | 8.30k | for (n = 0; n < 5; n++) { |
2015 | 6.92k | int key_ref = 0; |
2016 | 6.92k | if (*(op + n) == -1) |
2017 | 1.38k | continue; /* unused entry: skip */ |
2018 | 5.53k | key_ref = file->prop_attr[5 + n] & 0x0F; |
2019 | 5.53k | switch (0xF0 & file->prop_attr[5 + n]) { |
2020 | 1.51k | case 0x00: |
2021 | 1.51k | sc_file_add_acl_entry(file, *(op + n), SC_AC_NONE, |
2022 | 1.51k | SC_AC_KEY_REF_NONE); |
2023 | 1.51k | break; |
2024 | 260 | case 0x10: |
2025 | | /* this tag is omitted in official code |
2026 | | case 0x20: |
2027 | | */ |
2028 | 990 | case 0x30: |
2029 | 990 | sc_file_add_acl_entry(file, *(op + n), SC_AC_CHV, |
2030 | 990 | key_ref); |
2031 | 990 | break; |
2032 | 617 | case 0x40: |
2033 | 617 | sc_file_add_acl_entry(file, *(op + n), SC_AC_TERM, |
2034 | 617 | key_ref); |
2035 | 617 | break; |
2036 | 733 | case 0xF0: |
2037 | 733 | sc_file_add_acl_entry(file, *(op + n), SC_AC_NEVER, |
2038 | 733 | SC_AC_KEY_REF_NONE); |
2039 | 733 | break; |
2040 | 1.67k | default: |
2041 | 1.67k | sc_file_add_acl_entry(file, *(op + n), SC_AC_UNKNOWN, |
2042 | 1.67k | SC_AC_KEY_REF_NONE); |
2043 | 1.67k | break; |
2044 | 5.53k | } |
2045 | 5.53k | } |
2046 | | /* NOTE: Following bytes are described at DNIe manual pg 36, but No |
2047 | | documentation about what to do with following data is provided... |
2048 | | logs suggest that they are neither generated nor handled. |
2049 | | |
2050 | | UPDATE: these additional bytes are received when FileDescriptor tag |
2051 | | is 0x15 (EF for keys) |
2052 | | */ |
2053 | 1.38k | if (file->prop_attr[0] == 0x15) { |
2054 | 260 | sc_log(card->ctx, |
2055 | 260 | "Processing flags for Cryptographic key files"); |
2056 | | /* byte 10 (if present) shows Control Flags for security files */ |
2057 | | /* bytes 11 and 12 (if present) states Control bytes for |
2058 | | RSA crypto files */ |
2059 | | /* TODO: write when know what to do */ |
2060 | 260 | } |
2061 | 1.38k | res = SC_SUCCESS; /* arriving here means success */ |
2062 | 4.62k | dnie_process_fci_end: |
2063 | 4.62k | LOG_FUNC_RETURN(card->ctx, res); |
2064 | 4.62k | } |
2065 | | |
2066 | | /* |
2067 | | * PIN related functions |
2068 | | * NOTE: |
2069 | | * DNIe manual says only about CHV1 PIN verify, but several sources talks |
2070 | | * about the ability to also handle CHV1 PIN change |
2071 | | * So prepare code to eventually support |
2072 | | * |
2073 | | * Anyway pin unlock is not available: no way to get PUK as these code is |
2074 | | * obtained by mean of user fingerprint, only available at police station |
2075 | | */ |
2076 | | |
2077 | | /** |
2078 | | * Change PIN. |
2079 | | * |
2080 | | * Not implemented yet, as current availability for DNIe user driver |
2081 | | * is unknown |
2082 | | * |
2083 | | * @param card Pointer to Card Driver data structure |
2084 | | * @param data Pointer to Pin data structure |
2085 | | * @return SC_SUCCESS if ok; else error code |
2086 | | */ |
2087 | | static int dnie_pin_change(struct sc_card *card, struct sc_pin_cmd_data * data) |
2088 | 0 | { |
2089 | 0 | int res=SC_SUCCESS; |
2090 | 0 | LOG_FUNC_CALLED(card->ctx); |
2091 | | /* Ensure that secure channel is established from reset */ |
2092 | 0 | res = cwa_create_secure_channel(card, GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_ON); |
2093 | 0 | LOG_TEST_RET(card->ctx, res, "Establish SM failed"); |
2094 | 0 | LOG_FUNC_RETURN(card->ctx,SC_ERROR_NOT_SUPPORTED); |
2095 | 0 | } |
2096 | | |
2097 | | /** |
2098 | | * Verify PIN. |
2099 | | * |
2100 | | * Initialize SM and send pin verify CHV1 command to DNIe |
2101 | | * |
2102 | | * @param card Pointer to Card Driver data structure |
2103 | | * @param data Pointer to Pin data structure |
2104 | | * @param tries_left; on fail stores the number of tries left before car lock |
2105 | | * @return SC_SUCCESS if ok, else error code; on pin incorrect also sets tries_left |
2106 | | */ |
2107 | | static int dnie_pin_verify(struct sc_card *card, |
2108 | | struct sc_pin_cmd_data *data, int *tries_left) |
2109 | 0 | { |
2110 | 0 | int res=SC_SUCCESS; |
2111 | 0 | sc_apdu_t apdu; |
2112 | |
|
2113 | 0 | u8 pinbuffer[SC_MAX_APDU_BUFFER_SIZE]; |
2114 | 0 | int pinlen = 0; |
2115 | 0 | int padding = 0; |
2116 | |
|
2117 | 0 | LOG_FUNC_CALLED(card->ctx); |
2118 | | /* ensure that secure channel is established from reset */ |
2119 | 0 | if (card->atr.value[15] >= DNIE_30_VERSION) { |
2120 | | /* the provider should be prepared for using PIN information */ |
2121 | 0 | sc_log(card->ctx, "DNIe 3.0 detected doing PIN initialization"); |
2122 | 0 | dnie_change_cwa_provider_to_pin(card); |
2123 | 0 | } |
2124 | 0 | res = cwa_create_secure_channel(card, GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_ON); |
2125 | 0 | LOG_TEST_RET(card->ctx, res, "Establish SM failed"); |
2126 | | |
2127 | | /* compose pin data to be inserted in apdu */ |
2128 | 0 | if (data->flags & SC_PIN_CMD_NEED_PADDING) |
2129 | 0 | padding = 1; |
2130 | 0 | data->pin1.offset = 0; |
2131 | 0 | res = sc_build_pin(pinbuffer, sizeof(pinbuffer), &data->pin1, padding); |
2132 | 0 | if (res < 0) |
2133 | 0 | LOG_FUNC_RETURN(card->ctx, res); |
2134 | 0 | pinlen = res; |
2135 | | |
2136 | | /* compose apdu */ |
2137 | 0 | dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, 0x00, 0, pinlen, |
2138 | 0 | NULL, 0, pinbuffer, pinlen); |
2139 | | |
2140 | | /* and send to card through virtual channel */ |
2141 | 0 | res = sc_transmit_apdu(card, &apdu); |
2142 | 0 | if (res != SC_SUCCESS) { |
2143 | 0 | LOG_TEST_RET(card->ctx, res, "VERIFY APDU Transmit fail"); |
2144 | 0 | } |
2145 | | |
2146 | | /* check response and if requested setup tries_left */ |
2147 | 0 | if (tries_left != NULL) { /* returning tries_left count is requested */ |
2148 | 0 | if ((apdu.sw1 == 0x63) && ((apdu.sw2 & 0xF0) == 0xC0)) { |
2149 | 0 | *tries_left = apdu.sw2 & 0x0F; |
2150 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT); |
2151 | 0 | } |
2152 | 0 | } |
2153 | 0 | res = dnie_check_sw(card, apdu.sw1, apdu.sw2); /* not a pinerr: parse result */ |
2154 | | |
2155 | | /* ensure that secure channel is established after a PIN channel in 3.0 */ |
2156 | 0 | if (card->atr.value[15] >= DNIE_30_VERSION) { |
2157 | 0 | sc_log(card->ctx, "DNIe 3.0 detected => re-establish secure channel"); |
2158 | 0 | dnie_change_cwa_provider_to_secure(card); |
2159 | 0 | if (res == SC_SUCCESS) { |
2160 | 0 | res = cwa_create_secure_channel(card, GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_ON); |
2161 | 0 | } |
2162 | 0 | } |
2163 | |
|
2164 | 0 | LOG_FUNC_RETURN(card->ctx, res); |
2165 | 0 | } |
2166 | | |
2167 | | /* pin_cmd: verify/change/unblock command; optionally using the |
2168 | | * card's pin pad if supported. |
2169 | | */ |
2170 | | |
2171 | | /** |
2172 | | * OpenDNIe implementation for Pin_Cmd() card driver command. |
2173 | | * |
2174 | | * @param card Pointer to Card Driver data structure |
2175 | | * @param data Pointer to Pin data structure |
2176 | | * @param tries_left; if pin_verify() operation, on incorrect pin stores the number of tries left before car lock |
2177 | | * @return SC_SUCCESS if ok, else error code; on pin incorrect also sets tries_left |
2178 | | */ |
2179 | | static int dnie_pin_cmd(struct sc_card *card, |
2180 | | struct sc_pin_cmd_data *data, int *tries_left) |
2181 | 132 | { |
2182 | 132 | int res = SC_SUCCESS; |
2183 | 132 | int lc = SC_CARDCTRL_LIFECYCLE_USER; |
2184 | | |
2185 | 132 | if ((card == NULL) || (card->ctx == NULL) || (data == NULL)) |
2186 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
2187 | 132 | LOG_FUNC_CALLED(card->ctx); |
2188 | | |
2189 | | /* |
2190 | | * some flags and settings from documentation |
2191 | | * No (easy) way to handle pinpad through SM, so disable it |
2192 | | */ |
2193 | 132 | data->flags &= ~SC_PIN_CMD_NEED_PADDING; /* no pin padding */ |
2194 | 132 | data->flags &= ~SC_PIN_CMD_USE_PINPAD; /* cannot handle pinpad */ |
2195 | | |
2196 | | /* ensure that card is in USER Lifecycle */ |
2197 | 132 | res = dnie_card_ctl(card, SC_CARDCTL_LIFECYCLE_GET, &lc); |
2198 | 132 | LOG_TEST_RET(card->ctx, res, "Cannot get card LC status"); |
2199 | 132 | if (lc != SC_CARDCTRL_LIFECYCLE_USER) { |
2200 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_CARD); |
2201 | 0 | } |
2202 | | |
2203 | | /* only allow changes on CHV pin ) */ |
2204 | 132 | switch (data->pin_type) { |
2205 | 132 | case SC_AC_CHV: /* Card Holder Verifier */ |
2206 | 132 | break; |
2207 | 0 | case SC_AC_TERM: /* Terminal auth */ |
2208 | 0 | case SC_AC_PRO: /* SM auth */ |
2209 | 0 | case SC_AC_AUT: /* Key auth */ |
2210 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); |
2211 | 0 | default: |
2212 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
2213 | 132 | } |
2214 | | /* This DNIe driver only supports VERIFY operation */ |
2215 | 132 | switch (data->cmd) { |
2216 | 0 | case SC_PIN_CMD_VERIFY: |
2217 | 0 | res = dnie_pin_verify(card,data,tries_left); |
2218 | 0 | break; |
2219 | 0 | case SC_PIN_CMD_CHANGE: |
2220 | 0 | res = dnie_pin_change(card,data); |
2221 | 0 | break; |
2222 | 0 | case SC_PIN_CMD_UNBLOCK: |
2223 | 132 | case SC_PIN_CMD_GET_INFO: |
2224 | 132 | res= SC_ERROR_NOT_SUPPORTED; |
2225 | 132 | break; |
2226 | 0 | default: |
2227 | 0 | res= SC_ERROR_INVALID_ARGUMENTS; |
2228 | 0 | break; |
2229 | 132 | } |
2230 | | /* return result */ |
2231 | 132 | LOG_FUNC_RETURN(card->ctx, res); |
2232 | 132 | } |
2233 | | |
2234 | | /**********************************************************************/ |
2235 | | |
2236 | | /** |
2237 | | * Internal function to initialize card driver function pointers. |
2238 | | * |
2239 | | * This is done by getting a copy for iso7816 card operations, |
2240 | | * and replace every DNIe specific functions |
2241 | | * |
2242 | | * @return DNIe card driver data, or null on failure |
2243 | | */ |
2244 | | static sc_card_driver_t *get_dnie_driver(void) |
2245 | 99.7k | { |
2246 | 99.7k | sc_card_driver_t *iso_drv = sc_get_iso7816_driver(); |
2247 | | |
2248 | | /* memcpy() from standard iso7816 declared operations */ |
2249 | 99.7k | if (iso_ops == NULL) |
2250 | 10 | iso_ops = iso_drv->ops; |
2251 | 99.7k | dnie_ops = *iso_drv->ops; |
2252 | | |
2253 | | /* fill card specific function pointers */ |
2254 | | /* NULL means that function is not supported neither by DNIe nor iso7816.c */ |
2255 | | /* if pointer is omitted, default ISO7816 function will be used */ |
2256 | | |
2257 | | /* initialization */ |
2258 | 99.7k | dnie_ops.match_card = dnie_match_card; |
2259 | 99.7k | dnie_ops.init = dnie_init; |
2260 | 99.7k | dnie_ops.finish = dnie_finish; |
2261 | | |
2262 | | /* iso7816-4 functions */ |
2263 | 99.7k | dnie_ops.read_binary = dnie_read_binary; |
2264 | 99.7k | dnie_ops.write_binary = NULL; |
2265 | 99.7k | dnie_ops.update_binary = NULL; |
2266 | 99.7k | dnie_ops.erase_binary = NULL; |
2267 | 99.7k | dnie_ops.read_record = NULL; |
2268 | 99.7k | dnie_ops.write_record = NULL; |
2269 | 99.7k | dnie_ops.append_record = NULL; |
2270 | 99.7k | dnie_ops.update_record = NULL; |
2271 | 99.7k | dnie_ops.select_file = dnie_select_file; |
2272 | 99.7k | dnie_ops.get_challenge = dnie_get_challenge; |
2273 | | |
2274 | | /* iso7816-8 functions */ |
2275 | 99.7k | dnie_ops.verify = NULL; |
2276 | 99.7k | dnie_ops.logout = dnie_logout; |
2277 | | /* dnie_ops.restore_security_env */ |
2278 | 99.7k | dnie_ops.set_security_env = dnie_set_security_env; |
2279 | 99.7k | dnie_ops.decipher = dnie_decipher; |
2280 | 99.7k | dnie_ops.compute_signature = dnie_compute_signature; |
2281 | 99.7k | dnie_ops.change_reference_data = NULL; |
2282 | 99.7k | dnie_ops.reset_retry_counter = NULL; |
2283 | | |
2284 | | /* iso7816-9 functions */ |
2285 | 99.7k | dnie_ops.create_file = NULL; |
2286 | 99.7k | dnie_ops.delete_file = NULL; |
2287 | 99.7k | dnie_ops.list_files = dnie_list_files; |
2288 | 99.7k | dnie_ops.check_sw = dnie_check_sw; |
2289 | 99.7k | dnie_ops.card_ctl = dnie_card_ctl; |
2290 | 99.7k | dnie_ops.process_fci = dnie_process_fci; |
2291 | | /* dnie_ops.construct_fci */ |
2292 | 99.7k | dnie_ops.pin_cmd = dnie_pin_cmd; |
2293 | 99.7k | dnie_ops.get_data = NULL; |
2294 | 99.7k | dnie_ops.put_data = NULL; |
2295 | 99.7k | dnie_ops.delete_record = NULL; |
2296 | | |
2297 | 99.7k | return &dnie_driver; |
2298 | 99.7k | } |
2299 | | |
2300 | | /** |
2301 | | * Entry point for (static) OpenDNIe card driver. |
2302 | | * |
2303 | | * This is the only public function on this module |
2304 | | * |
2305 | | * @return properly initialized array pointer to card driver operations |
2306 | | */ |
2307 | | sc_card_driver_t *sc_get_dnie_driver(void) |
2308 | 99.7k | { |
2309 | 99.7k | return get_dnie_driver(); |
2310 | 99.7k | } |
2311 | | |
2312 | | #undef __CARD_DNIE_C__ |
2313 | | |
2314 | | #endif /* ENABLE_OPENSSL */ |