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