pinpad support change
[gnuk/gnuk.git] / src / openpgp.c
1 /*
2  * openpgp.c -- OpenPGP card protocol support
3  *
4  * Copyright (C) 2010, 2011 Free Software Initiative of Japan
5  * Author: NIIBE Yutaka <gniibe@fsij.org>
6  *
7  * This file is a part of Gnuk, a GnuPG USB Token implementation.
8  *
9  * Gnuk is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "config.h"
25 #include "ch.h"
26 #include "hal.h"
27 #include "gnuk.h"
28 #include "openpgp.h"
29 #include "polarssl/config.h"
30 #include "polarssl/sha1.h"
31
32 #define INS_VERIFY                              0x20
33 #define INS_CHANGE_REFERENCE_DATA               0x24
34 #define INS_PSO                                 0x2a
35 #define INS_RESET_RETRY_COUNTER                 0x2c
36 #define INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR    0x47
37 #define INS_INTERNAL_AUTHENTICATE               0x88
38 #define INS_SELECT_FILE                         0xa4
39 #define INS_READ_BINARY                         0xb0
40 #define INS_GET_DATA                            0xca
41 #define INS_WRITE_BINARY                        0xd0
42 #define INS_UPDATE_BINARY                       0xd6
43 #define INS_PUT_DATA                            0xda
44 #define INS_PUT_DATA_ODD                        0xdb    /* For key import */
45
46 static const uint8_t
47 select_file_TOP_result[] __attribute__ ((aligned (1))) = {
48   0x00, 0x00,        /* unused */
49   0x00, 0x00,        /* number of bytes in this directory: to be filled */
50   0x3f, 0x00,        /* field of selected file: MF, 3f00 */
51   0x38,                 /* it's DF */
52   0xff,                 /* unused */
53   0xff, 0x44, 0x44,     /* access conditions */
54   0x01,                 /* status of the selected file (OK, unblocked) */
55   0x05,                 /* number of bytes of data follow */
56     0x03,                       /* Features: unused */
57     0x01,                       /* number of subdirectories (OpenPGP) */
58     0x01,                       /* number of elementary files (SerialNo) */
59     0x00,                       /* number of secret codes */
60     0x00,                       /* Unused */
61   0x00, 0x00            /* PIN status: OK, PIN blocked?: No */
62 };
63
64 void
65 set_res_apdu (uint8_t sw1, uint8_t sw2)
66 {
67   res_APDU_size = 2;
68   res_APDU[0] = sw1;
69   res_APDU[1] = sw2;
70 }
71
72 #define FILE_NONE       0
73 #define FILE_DF_OPENPGP 1
74 #define FILE_MF         2
75 #define FILE_EF_DIR     3
76 #define FILE_EF_SERIAL  4
77 #define FILE_EF_CH_CERTIFICATE  5
78 #define FILE_EF_RANDOM          6
79
80 static uint8_t file_selection;
81
82 static void
83 gpg_init (void)
84 {
85   const uint8_t *flash_data_start;
86
87   file_selection = FILE_NONE;
88   flash_data_start = flash_init ();
89   gpg_data_scan (flash_data_start);
90 }
91
92 static void
93 gpg_fini (void)
94 {
95   ac_fini ();
96 }
97
98 #if defined(PINPAD_SUPPORT)
99 /* 
100  * Let user input PIN string.
101  * Return length of the string.
102  * The string itself is in PIN_INPUT_BUFFER.
103  */
104 static int
105 get_pinpad_input (int msg_code)
106 {
107   int r;
108
109   chEvtSignal (main_thread, LED_INPUT_MODE);
110   r = pinpad_getline (msg_code, MS2ST (8000));
111   chEvtSignal (main_thread, LED_STATUS_MODE);
112   return r;
113 }
114 #endif
115
116 static void
117 cmd_verify (void)
118 {
119   int len;
120   uint8_t p2 = cmd_APDU[3];
121   int r;
122   int data_start = 5;
123   const uint8_t *pw;
124
125   DEBUG_INFO (" - VERIFY\r\n");
126   DEBUG_BYTE (p2);
127
128   len = cmd_APDU[4];
129   if (len == 0)                 /* extended length */
130     {
131       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
132       data_start = 7;
133     }
134
135   pw = &cmd_APDU[data_start];
136
137   if (p2 == 0x81)
138     r = verify_pso_cds (pw, len);
139   else if (p2 == 0x82)
140     r = verify_other (pw, len);
141   else
142     r = verify_admin (pw, len);
143
144   if (r < 0)
145     {
146       DEBUG_INFO ("failed\r\n");
147       GPG_SECURITY_FAILURE ();
148     }
149   else if (r == 0)
150     {
151       DEBUG_INFO ("blocked\r\n");
152       GPG_SECURITY_AUTH_BLOCKED ();
153     }
154   else
155     {
156       DEBUG_INFO ("good\r\n");
157       GPG_SUCCESS ();
158     }
159 }
160
161 int
162 gpg_change_keystring (int who_old, const uint8_t *old_ks,
163                       int who_new, const uint8_t *new_ks)
164 {
165   int r;
166   int prv_keys_exist = 0;
167
168   r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, who_old, old_ks);
169   if (r < 0)
170     return r;
171
172   if (r > 0)
173     prv_keys_exist++;
174
175   r = gpg_do_chks_prvkey (GPG_KEY_FOR_SIGNING, who_old, old_ks,
176                           who_new, new_ks);
177   if (r < 0)
178     return -2;
179
180   r = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, who_old, old_ks);
181   if (r < 0)
182     return r;
183
184   if (r > 0)
185     prv_keys_exist++;
186
187   r = gpg_do_chks_prvkey (GPG_KEY_FOR_DECRYPTION, who_old, old_ks,
188                           who_new, new_ks);
189   if (r < 0)
190     return -2;
191
192   r = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, who_old, old_ks);
193   if (r < 0)
194     return r;
195
196   if (r > 0)
197     prv_keys_exist++;
198
199   r = gpg_do_chks_prvkey (GPG_KEY_FOR_AUTHENTICATION, who_old, old_ks,
200                           who_new, new_ks);
201   if (r < 0)
202     return -2;
203
204   if (prv_keys_exist)
205     return 1;
206   else
207     return 0;
208 }
209
210 static void
211 cmd_change_password (void)
212 {
213   uint8_t old_ks[KEYSTRING_MD_SIZE];
214   uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
215   uint8_t *new_ks = &new_ks0[1];
216   uint8_t p1 = cmd_APDU[2];     /* 0: change (old+new), 1: exchange (new) */
217   uint8_t p2 = cmd_APDU[3];
218   int len;
219   const uint8_t *pw;
220   const uint8_t *newpw;
221   int pw_len, newpw_len;
222   int who = p2 - 0x80;
223   int r;
224
225   DEBUG_INFO ("Change PW\r\n");
226   DEBUG_BYTE (who);
227
228   len = cmd_APDU[4];
229   pw = &cmd_APDU[5];
230   if (len == 0)                 /* extended length */
231     {
232       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
233       pw += 2;
234     }
235
236   if (p1 != 0)
237     {
238       GPG_FUNCTION_NOT_SUPPORTED();
239       return;
240     }
241
242   if (who == BY_USER)                   /* PW1 */
243     {
244       const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
245
246       pw_len = verify_user_0 (pw, len, -1, ks_pw1);
247
248       if (pw_len < 0)
249         {
250           DEBUG_INFO ("permission denied.\r\n");
251           GPG_SECURITY_FAILURE ();
252           return;
253         }
254       else if (pw_len == 0)
255         {
256           DEBUG_INFO ("blocked.\r\n");
257           GPG_SECURITY_AUTH_BLOCKED ();
258           return;
259         }
260       else
261         {
262           newpw = pw + pw_len;
263           newpw_len = len - pw_len;
264         }
265     }
266   else                          /* PW3 (0x83) */
267     {
268       pw_len = verify_admin_0 (pw, len, -1);
269
270       if (pw_len < 0)
271         {
272           DEBUG_INFO ("permission denied.\r\n");
273           GPG_SECURITY_FAILURE ();
274           return;
275         }
276       else if (pw_len == 0)
277         {
278           DEBUG_INFO ("blocked.\r\n");
279           GPG_SECURITY_AUTH_BLOCKED ();
280           return;
281         }
282       else
283         {
284           newpw = pw + pw_len;
285           newpw_len = len - pw_len;
286           gpg_set_pw3 (newpw, newpw_len);
287         }
288     }
289
290   sha1 (pw, pw_len, old_ks);
291   sha1 (newpw, newpw_len, new_ks);
292   new_ks0[0] = newpw_len;
293
294   r = gpg_change_keystring (who, old_ks, who, new_ks);
295   if (r <= -2)
296     {
297       DEBUG_INFO ("memory error.\r\n");
298       GPG_MEMORY_FAILURE ();
299     }
300   else if (r < 0)
301     {
302       DEBUG_INFO ("security error.\r\n");
303       GPG_SECURITY_FAILURE ();
304     }
305   else if (r == 0 && who == BY_USER)    /* no prvkey */
306     {
307       gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
308       ac_reset_pso_cds ();
309       ac_reset_other ();
310       DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
311       GPG_SUCCESS ();
312     }
313   else if (r > 0 && who == BY_USER)
314     {
315       gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
316       ac_reset_pso_cds ();
317       ac_reset_other ();
318       DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
319       GPG_SUCCESS ();
320     }
321   else                          /* r >= 0 && who == BY_ADMIN */
322     {
323       DEBUG_INFO ("done.\r\n");
324       ac_reset_admin ();
325       GPG_SUCCESS ();
326     }
327 }
328
329 static void
330 cmd_reset_user_password (void)
331 {
332   uint8_t p1 = cmd_APDU[2];
333   int len;
334   const uint8_t *pw;
335   const uint8_t *newpw;
336   int pw_len, newpw_len;
337   int r;
338   uint8_t new_ks0[KEYSTRING_MD_SIZE+1];
339   uint8_t *new_ks = &new_ks0[1];
340
341   DEBUG_INFO ("Reset PW1\r\n");
342   DEBUG_BYTE (p1);
343
344   len = cmd_APDU[4];
345   pw = &cmd_APDU[5];
346   if (len == 0)                 /* extended length */
347     {
348       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
349       pw += 2;
350     }
351
352   if (p1 == 0x00)               /* by User with Reseting Code */
353     {
354       const uint8_t *ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
355       uint8_t old_ks[KEYSTRING_MD_SIZE];
356
357       if (gpg_pw_locked (PW_ERR_RC))
358         {
359           DEBUG_INFO ("blocked.\r\n");
360           GPG_SECURITY_AUTH_BLOCKED ();
361           return;
362         }
363
364       if (ks_rc == NULL)
365         {
366           DEBUG_INFO ("security error.\r\n");
367           GPG_SECURITY_FAILURE ();
368           return;
369         }
370
371       pw_len = ks_rc[0];
372       newpw = pw + pw_len;
373       newpw_len = len - pw_len;
374       sha1 (pw, pw_len, old_ks);
375       sha1 (newpw, newpw_len, new_ks);
376       new_ks0[0] = newpw_len;
377       r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks);
378       if (r <= -2)
379         {
380           DEBUG_INFO ("memory error.\r\n");
381           GPG_MEMORY_FAILURE ();
382         }
383       else if (r < 0)
384         {
385         sec_fail:
386           DEBUG_INFO ("failed.\r\n");
387           gpg_pw_increment_err_counter (PW_ERR_RC);
388           GPG_SECURITY_FAILURE ();
389         }
390       else if (r == 0)
391         {
392           if (memcmp (ks_rc+1, old_ks, KEYSTRING_MD_SIZE) != 0)
393             goto sec_fail;
394           DEBUG_INFO ("done (no prvkey).\r\n");
395           gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0,
396                                KEYSTRING_SIZE_PW1);
397           ac_reset_pso_cds ();
398           ac_reset_other ();
399           gpg_pw_reset_err_counter (PW_ERR_RC);
400           gpg_pw_reset_err_counter (PW_ERR_PW1);
401           GPG_SUCCESS ();
402         }
403       else
404         {
405           DEBUG_INFO ("done.\r\n");
406           ac_reset_pso_cds ();
407           ac_reset_other ();
408           gpg_pw_reset_err_counter (PW_ERR_RC);
409           gpg_pw_reset_err_counter (PW_ERR_PW1);
410           GPG_SUCCESS ();
411         }
412     }
413   else                          /* by Admin (p1 == 0x02) */
414     {
415       const uint8_t *old_ks = keystring_md_pw3;
416
417       if (!ac_check_status (AC_ADMIN_AUTHORIZED))
418         {
419           DEBUG_INFO ("permission denied.\r\n");
420           GPG_SECURITY_FAILURE ();
421           return;
422         }
423
424       newpw_len = len;
425       newpw = pw;
426       sha1 (newpw, newpw_len, new_ks);
427       new_ks0[0] = newpw_len;
428       r = gpg_change_keystring (admin_authorized, old_ks, BY_USER, new_ks);
429       if (r <= -2)
430         {
431           DEBUG_INFO ("memory error.\r\n");
432           GPG_MEMORY_FAILURE ();
433         }
434       else if (r < 0)
435         {
436           DEBUG_INFO ("security error.\r\n");
437           GPG_SECURITY_FAILURE ();
438         }
439       else if (r == 0)
440         {
441           DEBUG_INFO ("done (no privkey).\r\n");
442           gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0,
443                                KEYSTRING_SIZE_PW1);
444           ac_reset_pso_cds ();
445           ac_reset_other ();
446           gpg_pw_reset_err_counter (PW_ERR_PW1);
447           GPG_SUCCESS ();
448         }
449       else
450         {
451           DEBUG_INFO ("done.\r\n");
452           ac_reset_pso_cds ();
453           ac_reset_other ();
454           gpg_pw_reset_err_counter (PW_ERR_PW1);
455           GPG_SUCCESS ();
456         }
457     }
458 }
459
460 static void
461 cmd_put_data (void)
462 {
463   uint8_t *data;
464   uint16_t tag;
465   int len;
466
467   DEBUG_INFO (" - PUT DATA\r\n");
468
469   if (file_selection != FILE_DF_OPENPGP)
470     GPG_NO_RECORD();
471
472   tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
473   data = &cmd_APDU[5];
474
475   len = cmd_APDU_size - 5;
476   if (len >= 256)
477     /* extended Lc */
478     {
479       data += 2;
480       len -= 2;
481     }
482
483   gpg_do_put_data (tag, data, len);
484 }
485
486 static void
487 cmd_pgp_gakp (void)
488 {
489   DEBUG_INFO (" - Generate Asymmetric Key Pair\r\n");
490   DEBUG_BYTE (cmd_APDU[2]);
491
492   if (cmd_APDU[2] == 0x81)
493     /* Get public key */
494     {
495       if (cmd_APDU[4] == 0)
496         gpg_do_public_key (cmd_APDU[7]);
497       else
498         gpg_do_public_key (cmd_APDU[5]);
499     }
500   else
501     {                                   /* Generate key pair */
502       if (!ac_check_status (AC_ADMIN_AUTHORIZED))
503         GPG_SECURITY_FAILURE ();
504
505       /* XXX: Not yet supported */
506       GPG_ERROR ();
507     }
508 }
509
510 static void
511 cmd_read_binary (void)
512 {
513   DEBUG_INFO (" - Read binary\r\n");
514
515   if (file_selection == FILE_EF_SERIAL)
516     {
517       if (cmd_APDU[3] >= 6)
518         GPG_BAD_P0_P1 ();
519       else
520         {
521           gpg_do_get_data (0x004f, 1); /* AID */
522           res_APDU[0] = 0x5a;
523         }
524     }
525   else
526     GPG_NO_RECORD();
527 }
528
529 static void
530 cmd_select_file (void)
531 {
532   if (cmd_APDU[2] == 4) /* Selection by DF name: it must be OpenPGP card */
533     {
534       DEBUG_INFO (" - select DF by name\r\n");
535
536       /*
537        * P2 == 0, LC=6, name = D2 76 00 01 24 01
538        */
539
540       file_selection = FILE_DF_OPENPGP;
541       if (cmd_APDU[3] == 0x0c)  /* No FCI */
542         GPG_SUCCESS ();
543       else
544         {
545           gpg_do_get_data (0x004f, 1); /* AID */
546           memmove (res_APDU+2, res_APDU, res_APDU_size);
547           res_APDU[0] = 0x6f;
548           res_APDU[1] = 0x12;
549           res_APDU[2] = 0x84;   /* overwrite: DF name */
550           res_APDU_size += 2;
551         }
552     }
553   else if (cmd_APDU[4] == 2
554            && cmd_APDU[5] == 0x2f && cmd_APDU[6] == 0x02)
555     {
556       DEBUG_INFO (" - select 0x2f02 EF\r\n");
557       /*
558        * MF.EF-GDO -- Serial number of the card and name of the owner
559        */
560       GPG_SUCCESS ();
561       file_selection = FILE_EF_SERIAL;
562     }
563   else if (cmd_APDU[4] == 2
564            && cmd_APDU[5] == 0x3f && cmd_APDU[6] == 0x00)
565     {
566       DEBUG_INFO (" - select ROOT MF\r\n");
567       if (cmd_APDU[3] == 0x0c)
568         {
569           GPG_SUCCESS ();
570         }
571       else
572         {
573           int len = sizeof (select_file_TOP_result);
574
575           res_APDU_size = 2 + len;
576           memcpy (res_APDU, select_file_TOP_result, len);
577           res_APDU[2] = (data_objects_number_of_bytes & 0xff);
578           res_APDU[3] = (data_objects_number_of_bytes >> 8);
579           res_APDU[len] = 0x90;
580           res_APDU[len+1] = 0x00;
581         }
582
583       file_selection = FILE_MF;
584       ac_fini ();               /* Reset authentication */
585     }
586   else
587     {
588       DEBUG_INFO (" - select ?? \r\n");
589
590       file_selection = FILE_NONE;
591       GPG_NO_FILE ();
592     }
593 }
594
595 static void
596 cmd_get_data (void)
597 {
598   uint16_t tag = ((cmd_APDU[2]<<8) | cmd_APDU[3]);
599
600   DEBUG_INFO (" - Get Data\r\n");
601
602   if (file_selection != FILE_DF_OPENPGP)
603     GPG_NO_RECORD ();
604
605   gpg_do_get_data (tag, 0);
606 }
607
608 static void
609 cmd_pso (void)
610 {
611   int len = cmd_APDU[4];
612   int data_start = 5;
613   int r;
614
615   if (len == 0)
616     {
617       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
618       data_start = 7;
619     }
620
621   DEBUG_INFO (" - PSO: ");
622   DEBUG_WORD ((uint32_t)&r);
623   DEBUG_BINARY (cmd_APDU, cmd_APDU_size);
624
625   if (cmd_APDU[2] == 0x9e && cmd_APDU[3] == 0x9a)
626     {
627       if (!ac_check_status (AC_PSO_CDS_AUTHORIZED))
628         {
629           DEBUG_INFO ("security error.");
630           GPG_SECURITY_FAILURE ();
631           return;
632         }
633
634       if (cmd_APDU_size != 7 + 34 + 2  /* MD5 */
635           /* Header (with Extended Lc)=7, size of digestInfo, and Le=2-byte */
636           && cmd_APDU_size != 7 + 35 + 2  /* SHA1 / RIPEMD-160 */
637           && cmd_APDU_size != 7 + 47 + 2  /* SHA224 */
638           && cmd_APDU_size != 7 + 51 + 2  /* SHA256 */
639           && cmd_APDU_size != 7 + 67 + 2  /* SHA384 */
640           && cmd_APDU_size != 7 + 83 + 2) /* SHA512 */
641         {
642           DEBUG_INFO (" wrong length: ");
643           DEBUG_SHORT (cmd_APDU_size);
644           GPG_ERROR ();
645         }
646       else
647         {
648           DEBUG_SHORT (len);  /* Should be cmd_APDU_size - 8 [- 1] */
649           DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN);
650
651           r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
652                         &kd[GPG_KEY_FOR_SIGNING]);
653           if (r < 0)
654             {
655               ac_reset_pso_cds ();
656               GPG_ERROR ();
657             }
658           else
659             /* Success */
660             gpg_increment_digital_signature_counter ();
661         }
662     }
663   else if (cmd_APDU[2] == 0x80 && cmd_APDU[3] == 0x86)
664     {
665       DEBUG_SHORT (len);
666       DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN);
667
668       if (!ac_check_status (AC_OTHER_AUTHORIZED))
669         {
670           DEBUG_INFO ("security error.");
671           GPG_SECURITY_FAILURE ();
672           return;
673         }
674
675       /* Skip padding 0x00 */
676       data_start++;
677       len--;
678       r = rsa_decrypt (&cmd_APDU[data_start], res_APDU, len,
679                        &kd[GPG_KEY_FOR_DECRYPTION]);
680       if (r < 0)
681         GPG_ERROR ();
682     }
683   else
684     {
685       DEBUG_INFO (" - ??");
686       DEBUG_BYTE (cmd_APDU[2]);
687       DEBUG_INFO (" - ??");
688       DEBUG_BYTE (cmd_APDU[3]);
689       GPG_ERROR ();
690     }
691
692   DEBUG_INFO ("PSO done.\r\n");
693 }
694
695 static void
696 cmd_internal_authenticate (void)
697 {
698   int len = cmd_APDU[4];
699   int data_start = 5;
700   int r;
701
702   if (len == 0)
703     {
704       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
705       data_start = 7;
706     }
707
708   DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
709
710   if (cmd_APDU[2] == 0x00 && cmd_APDU[3] == 0x00)
711     {
712       DEBUG_SHORT (len);
713
714       if (!ac_check_status (AC_OTHER_AUTHORIZED))
715         {
716           DEBUG_INFO ("security error.");
717           GPG_SECURITY_FAILURE ();
718           return;
719         }
720
721       r = rsa_sign (&cmd_APDU[data_start], res_APDU, len,
722                     &kd[GPG_KEY_FOR_AUTHENTICATION]);
723       if (r < 0)
724         GPG_ERROR ();
725     }
726   else
727     {
728       DEBUG_INFO (" - ??");
729       DEBUG_BYTE (cmd_APDU[2]);
730       DEBUG_INFO (" - ??");
731       DEBUG_BYTE (cmd_APDU[3]);
732       GPG_ERROR ();
733     }
734
735   DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
736 }
737
738
739 static void
740 cmd_update_binary (void)
741 {
742   int len = cmd_APDU[4];
743   int data_start = 5;
744   uint16_t offset;
745   int r;
746
747   if (len == 0)
748     {
749       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
750       data_start = 7;
751     }
752
753   DEBUG_INFO (" - UPDATE BINARY\r\n");
754
755   if (!ac_check_status (AC_ADMIN_AUTHORIZED))
756     {
757       DEBUG_INFO ("security error.");
758       GPG_SECURITY_FAILURE ();
759       return;
760     }
761
762   if ((cmd_APDU[2] & 0x80))
763     if ((cmd_APDU[2] & 0x7f) <= FILEID_RANDOM)
764       {
765         file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f);
766         r = flash_erase_binary (file_selection - FILE_EF_CH_CERTIFICATE);
767         if (r < 0)
768           {
769             DEBUG_INFO ("memory error.\r\n");
770             GPG_MEMORY_FAILURE ();
771             return;
772           }
773
774         offset = 0;
775       }
776     else
777       {
778         GPG_NO_FILE ();
779         return;
780       }
781   else
782     {
783       if (file_selection != FILE_EF_CH_CERTIFICATE
784           && file_selection != FILE_EF_RANDOM)
785         {
786           GPG_COMMAND_NOT_ALLOWED ();
787           return;
788         }
789
790       offset = (cmd_APDU[2] << 8) | cmd_APDU[3];
791     }
792
793   DEBUG_SHORT (len);
794   DEBUG_SHORT (offset);
795
796   r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
797                           &cmd_APDU[data_start], len, offset);
798   if (r < 0)
799     {
800       DEBUG_INFO ("memory error.\r\n");
801       GPG_MEMORY_FAILURE ();
802       return;
803     }
804
805   GPG_SUCCESS ();
806   DEBUG_INFO ("UPDATE BINARY done.\r\n");
807 }
808
809
810 static void
811 cmd_write_binary (void)
812 {
813   int len = cmd_APDU[4];
814   int data_start = 5;
815   uint16_t offset;
816   int r;
817
818   if (len == 0)
819     {
820       len = (cmd_APDU[5]<<8) | cmd_APDU[6];
821       data_start = 7;
822     }
823
824   DEBUG_INFO (" - WRITE BINARY\r\n");
825
826   if (!ac_check_status (AC_ADMIN_AUTHORIZED))
827     {
828       DEBUG_INFO ("security error.");
829       GPG_SECURITY_FAILURE ();
830       return;
831     }
832
833   if ((cmd_APDU[2] & 0x80))
834     if ((cmd_APDU[2] & 0x7f) <= FILEID_SERIAL_NO)
835       {
836         file_selection = FILE_EF_CH_CERTIFICATE + (cmd_APDU[2] & 0x7f);
837         offset = 0;
838       }
839     else
840       {
841         GPG_NO_FILE ();
842         return;
843       }
844   else
845     {
846       if (file_selection != FILE_EF_CH_CERTIFICATE
847           && file_selection != FILE_EF_RANDOM
848           && file_selection != FILE_EF_SERIAL)
849         {
850           GPG_COMMAND_NOT_ALLOWED ();
851           return;
852         }
853
854       offset = (cmd_APDU[2] << 8) | cmd_APDU[3];
855     }
856
857   DEBUG_SHORT (len);
858   DEBUG_SHORT (offset);
859
860   r = flash_write_binary (file_selection - FILE_EF_CH_CERTIFICATE,
861                           &cmd_APDU[data_start], len, offset);
862   if (r < 0)
863     {
864       DEBUG_INFO ("memory error.\r\n");
865       GPG_MEMORY_FAILURE ();
866       return;
867     }
868
869   GPG_SUCCESS ();
870   DEBUG_INFO ("WRITE BINARY done.\r\n");
871 }
872
873
874 struct command
875 {
876   uint8_t command;
877   void (*cmd_handler) (void);
878 };
879
880 const struct command cmds[] = {
881   { INS_VERIFY, cmd_verify },
882   { INS_CHANGE_REFERENCE_DATA, cmd_change_password },
883   { INS_PSO, cmd_pso },
884   { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
885   { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
886   { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
887   { INS_SELECT_FILE, cmd_select_file },
888   { INS_READ_BINARY, cmd_read_binary },
889   { INS_GET_DATA, cmd_get_data },
890   { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
891   { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */
892   { INS_PUT_DATA, cmd_put_data },
893   { INS_PUT_DATA_ODD, cmd_put_data },
894 };
895 #define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
896
897 static void
898 process_command_apdu (void)
899 {
900   int i;
901   uint8_t cmd = cmd_APDU[1];
902
903   for (i = 0; i < NUM_CMDS; i++)
904     if (cmds[i].command == cmd)
905       break;
906
907   if (i < NUM_CMDS)
908     cmds[i].cmd_handler ();
909   else
910     {
911       DEBUG_INFO (" - ??");
912       DEBUG_BYTE (cmd);
913       GPG_NO_INS ();
914     }
915 }
916
917 msg_t
918 GPGthread (void *arg)
919 {
920   Thread *icc_thread = (Thread *)arg;
921
922   gpg_init ();
923
924   chEvtClear (ALL_EVENTS);
925
926   while (!chThdShouldTerminate ())
927     {
928       eventmask_t m = chEvtWaitOne (ALL_EVENTS);
929 #if defined(PINPAD_SUPPORT)
930       int len, pw_len, newpw_len;
931 #endif
932
933       DEBUG_INFO ("GPG!: ");
934
935       res_APDU_pointer = NULL;
936
937       if (m == EV_VERIFY_CMD_AVAILABLE)
938         {
939 #if defined(PINPAD_SUPPORT)
940           if (cmd_APDU[1] != INS_VERIFY)
941             {
942               GPG_CONDITION_NOT_SATISFIED ();
943               goto done;
944             }
945
946           pw_len = get_pinpad_input (PIN_INPUT_CURRENT);
947           if (pw_len < 0)
948             {
949               GPG_ERROR ();
950               goto done;
951             }
952           memcpy (&cmd_APDU[5], pin_input_buffer, pw_len);
953           cmd_APDU[4] = pw_len;
954           icc_data_size = 5 + pw_len;
955 #else
956           GPG_ERROR ();
957           goto done;
958 #endif
959         }
960       else if (m == EV_MODIFY_CMD_AVAILABLE)
961         {
962 #if defined(PINPAD_SUPPORT)
963           if (cmd_APDU[1] != INS_CHANGE_REFERENCE_DATA)
964             {
965               GPG_CONDITION_NOT_SATISFIED ();
966               goto done;
967             }
968
969           pw_len = get_pinpad_input (PIN_INPUT_CURRENT);
970           if (pw_len < 0)
971             {
972               GPG_ERROR ();
973               goto done;
974             }
975           memcpy (&cmd_APDU[5], pin_input_buffer, pw_len);
976
977           newpw_len = get_pinpad_input (PIN_INPUT_NEW);
978           if (newpw_len < 0)
979             {
980               GPG_ERROR ();
981               goto done;
982             }
983           memcpy (&cmd_APDU[5]+pw_len, pin_input_buffer, newpw_len);
984
985           len = get_pinpad_input (PIN_INPUT_CONFIRM);
986           if (len < 0)
987             {
988               GPG_ERROR ();
989               goto done;
990             }
991
992           if (len != newpw_len
993               || memcmp (&cmd_APDU[5]+pw_len, pin_input_buffer, len) != 0)
994             {
995               GPG_SECURITY_FAILURE ();
996               goto done;
997             }
998
999           len = cmd_APDU[4] = pw_len + newpw_len;
1000           icc_data_size = 5 + len;
1001 #else
1002           GPG_ERROR ();
1003           goto done;
1004 #endif
1005         }
1006       else if (m == EV_NOP)
1007         continue;
1008
1009       if (icc_data_size != 0)
1010         {
1011           process_command_apdu ();
1012         done:
1013           chEvtSignal (icc_thread, EV_EXEC_FINISHED);
1014         }
1015     }
1016
1017   gpg_fini ();
1018   return 0;
1019 }